Skip to content

Instantly share code, notes, and snippets.

@adamcichy
Created March 15, 2017 15:28
Show Gist options
  • Star 30 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save adamcichy/2d00c7a54009b4a9751ba513749c485e to your computer and use it in GitHub Desktop.
Save adamcichy/2d00c7a54009b4a9751ba513749c485e to your computer and use it in GitHub Desktop.
Determine if a UIImage is generally dark or generally light in Swift 3
extension CGImage {
var isDark: Bool {
get {
guard let imageData = self.dataProvider?.data else { return false }
guard let ptr = CFDataGetBytePtr(imageData) else { return false }
let length = CFDataGetLength(imageData)
let threshold = Int(Double(self.width * self.height) * 0.45)
var darkPixels = 0
for i in stride(from: 0, to: length, by: 4) {
let r = ptr[i]
let g = ptr[i + 1]
let b = ptr[i + 2]
let luminance = (0.299 * Double(r) + 0.587 * Double(g) + 0.114 * Double(b))
if luminance < 150 {
darkPixels += 1
if darkPixels > threshold {
return true
}
}
}
return false
}
}
}
extension UIImage {
var isDark: Bool {
get {
return self.cgImage?.isDark ?? false
}
}
}
@toniocrq
Copy link

toniocrq commented Feb 14, 2018

Hi, I'm trying this solution on my set of UIImages but it returns me always a true value on very bright images, I also resized the image but doesn't work anyway. Do you have any idea why your solution couldn't work. Thanks

//Resize Function
func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage {
        let scale = newWidth / image.size.width
        let newHeight = image.size.height * scale
        UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))

        image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return newImage!
    }

@alvincrisuy
Copy link

It seems like yes it is always returning true. @toniocrq have you solved this?

@toniocrq
Copy link

Hi @alvincrisuy, no i didn't. I found another algorithm and it worked. Thank you by the way.

@mmshivesh
Copy link

Any idea on which method works best?

@alvincrisuy
Copy link

@toniocrq do you have links/resources or can you also share the algorithm that worked for you? thank you in advanced.

@toniocrq
Copy link

toniocrq commented May 22, 2019

I calculated the brightness.
If the brightness is between 34 and 227 the image is good for me.

extension CGImage {
    var brightness: Double {
        get {
            let imageData = self.dataProvider?.data
            let ptr = CFDataGetBytePtr(imageData)
            var x = 0
            var result: Double = 0
            for _ in 0..<self.height {
                for _ in 0..<self.width {
                    let r = ptr![0]
                    let g = ptr![1]
                    let b = ptr![2]
                    result += (0.299 * Double(r) + 0.587 * Double(g) + 0.114 * Double(b))
                    x += 1
                }
            }
            let bright = result / Double (x)
            return bright
        }
    }
}
extension UIImage {
    var brightness: Double {
        get {
            return (self.cgImage?.brightness)!
        }
    }
}

@alvincrisuy
Copy link

Hi @toniocrq thank you for this! though what does 34-227 mean?

@toniocrq
Copy link

toniocrq commented May 28, 2019

@alvincrisuy It's a range that i use for the returned bright.
It goes from 0 to 255.
If the image's brightness is < 34 , the image is too dark, if is > 227 is too bright.

@iamtomcat
Copy link

Nevermind I reread it and it's fine, just jumping the gun thinking I had figured something out.

@rideflag-minh-huynh
Copy link

rideflag-minh-huynh commented Oct 21, 2021

@toniocrq this code is slightly incorrect, you are reading the same pixel every time in the for loop.

Here is my fix
`

       let pixels = self.width*self.height

       let bytesPerPixel = self.bitsPerPixel / self.bitsPerComponent

       var result: Double = 0

        for y in 0..<self.height {
            for x in 0..<self.width {
                let offset = (y * self.bytesPerRow) + (x * bytesPerPixel)
                let r = ptr![offset]
                let g = ptr![offset + 1]
                let b = ptr![offset + 2]

`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment