Skip to content

Instantly share code, notes, and snippets.

@dnedrow
Last active March 9, 2020 13:36
Show Gist options
  • Select an option

  • Save dnedrow/bc5b91b48d4f99d9fb7e48ccbfa2fed6 to your computer and use it in GitHub Desktop.

Select an option

Save dnedrow/bc5b91b48d4f99d9fb7e48ccbfa2fed6 to your computer and use it in GitHub Desktop.
This protocol defines functions for determining contrasting colors and other color related values.
// Created by Nedrow, David E on 3/25/19.
// Attribution 4.0 International (CC 4.0), see bottom.
import UIKit
// MARK: - UIColor+ContrastColor.swift
/// This protocol defines functions for determining contrasting colors and other
/// color related values.
public protocol ContrastColorProtocol {
/// Calculates the luminance of the given color.
///
/// - Parameter color: The color for which the luminance is needed.
/// - Returns: The luminance of the input color. If this could not be
/// calculated, nil is returned.
static func luminance(_ color: UIColor) -> Double?
/// Returns a color that is a contrast to the given color.
///
/// - Parameter color: The color for which a contrasting color is needed.
/// - Returns: The contrasting color.
static func contrastColor(_ color: UIColor) -> UIColor
/// Indicates whether a light contrast color is needed for this color instance.
///
/// - Returns: True if a light contrast color should be used with this color.
/// `nil` is returned if the calculation failed.
func useLightContrastingColor() -> Bool?
}
// MARK: - ContrastColorProtocol default implementation.
/// Default implementations for static ContrastColorProtocol functions.
public extension ContrastColorProtocol {
/// Default implementation of luminance(_ color: UIColor)
static func luminance(_ color: UIColor) -> Double? {
// These weightings were proposed by StackOverflow user Gacek in post:
// https://stackoverflow.com/a/1855903/1227012
let redWeight: CGFloat = 0.299
let greenWeight: CGFloat = 0.587 // The human eye favors the green spectrum.
let blueWeight: CGFloat = 0.114
let alphaWeight: CGFloat = 0.0 // Alpha is deliberately ignored.
var redValue: CGFloat = 0.0
var greenValue: CGFloat = 0.0
var blueValue: CGFloat = 0.0
var alphaValue: CGFloat = 0.0
if !color.getRed(&redValue, green: &greenValue, blue: &blueValue, alpha: &alphaValue) {
return nil
}
return Double((redWeight * redValue) + (greenWeight * greenValue) +
(blueWeight * blueValue) + (alphaWeight * alphaValue))
}
/// Default implementation of contrastColor(_ color: UIColor)
static func contrastColor(_ color: UIColor) -> UIColor {
fatalError("contrastColor(_:) has not been implemented")
}
}
// MARK: - ContrastColorProtocol instance methods.
extension UIColor: ContrastColorProtocol {
public func useLightContrastingColor() -> Bool? {
guard let thisLuminance = UIColor.luminance(self) else {
return nil
}
return !(thisLuminance >= 0.5)
}
}
// This work is licensed under Attribution 4.0 International (CC 4.0)
// You are free to:
// Share — copy and redistribute the material in any medium or format
// Adapt — remix, transform, and build upon the material
// for any purpose, even commercially.
//
// This license is acceptable for Free Cultural Works.
// The licensor cannot revoke these freedoms as long as you follow the license terms.
// See https://creativecommons.org/licenses/by/4.0/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment