Search code examples
iosswiftcore-graphicscifilter

How to change Brightness and Contrast with one UISlider with Swift


I am working on a Photo Filter App. I want to change Brightness and Contrast with a single slider. I can change them but when I jump to Contrast I loose Brightness changes. Wow can I keep the Brightness applied image and then continue with Contrast change.

 if sender.tag == 0 {
        
       
        self.coreImage = CIImage(image: (originalImage.image!))!
        
        
        let filter2 = CIFilter(name: "CIColorControls" )
        filter2!.setValue(coreImage, forKey: kCIInputImageKey)
        filter2?.setValue(sender.value, forKey: kCIInputBrightnessKey)
        
        brightnessValue = sender.value
        
        
        filter2!.setValue(coreImage, forKey: kCIInputImageKey)
        let filteredImageData2 = filter2!.value(forKey: kCIOutputImageKey) as! CIImage
        
        let filteredImageRef = ciContext.createCGImage(filteredImageData2, from: filteredImageData2.extent)
        let imageForButton = UIImage(cgImage: filteredImageRef!)
        
        
        
        originalImage.isHidden = true
        imageToFilter.image = imageForButton
    }
    
    else if sender.tag == 1 {

        
        self.coreImage = CIImage(image: (originalImage.image!)) ?? CIImage()
        
        let filter2 = CIFilter(name: "CIColorControls" )
        filter2!.setValue(coreImage, forKey: kCIInputImageKey)
        filter2?.setValue(sender.value, forKey: kCIInputContrastKey)
        
        filter2!.setValue(coreImage, forKey: kCIInputImageKey)
        let filteredImageData2 = filter2!.value(forKey: kCIOutputImageKey) as! CIImage
        
        let filteredImageRef = ciContext.createCGImage(filteredImageData2, from: filteredImageData2.extent)
        let imageForButton = UIImage(cgImage: filteredImageRef!)
        
        
        
        originalImage.isHidden = true
        imageToFilter.image = imageForButton


        }

and the following code controls the button and what to change

if (Lb == "Brightness") {
        sliderColor.tag = 0
        sliderColor.minimumValue = -1.0
        sliderColor.maximumValue = 1.0
        sliderColor.value = 0.0
        
    
        
    } else if (Lb == "Contrast") {
        sliderColor.tag = 1

        
        sliderColor.minimumValue = 0.0
        sliderColor.maximumValue = 4.0
        sliderColor.value = 1.0
        
        
    } 

I am aware of it is caused by the fact that I use originalImage everytime I change Brightness or Contrast. But if I change it to imageToFilter things get sloppy.

Any ideas?


Solution

  • As you have to keep reference and track for both filter key-value and apply both key filters at the same time while slider value changes.

    Here is the demo code.

    Note: As this is just a demo I used force unwrapping. You need to handle nil value.

    class ViewController: UIViewController {
        
        @IBOutlet weak var imageToFilter: UIImageView!
        
        public var brightness : Float = 0.0
        public var contrast : Float = 1.0
        
        var filter: CIFilter? = CIFilter(name: "CIColorControls")
        var originalImage = UIImage(named: "image_name")
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        func applyImageFilter(for image: UIImage) -> UIImage? {
            
            guard let sourceImage = CIImage(image: image),
                  let filter = self.filter else { return nil }
            
            filter.setValue(sourceImage, forKey: kCIInputImageKey)
            
            filter.setValue(self.contrast, forKey: kCIInputContrastKey)
            filter.setValue(self.brightness, forKey: kCIInputBrightnessKey)
            
            
            guard let output = filter.outputImage else { return nil }
            
            guard let outputCGImage = CIContext().createCGImage(output, from: output.extent) else { return nil }
            
            let filteredImage = UIImage(cgImage: outputCGImage, scale: image.scale, orientation: image.imageOrientation)
            
            return filteredImage
        }
        
        @IBAction func sliderValueChangeAction(_ sender: UISlider) {
            if sender.tag == 0 {
                self.brightness = sender.value
            
            } else if sender.tag == 1 {
                self.contrast = sender.value
            }
            
            imageToFilter.image = self.applyImageFilter(for: originalImage!)
        }
    }