From d7c660b3f911d097baadee17d3bb5b17a05dbe78 Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 10 Sep 2024 17:21:08 +0200 Subject: [PATCH] feat(ad-hoc): minor improvements (#346) * Set `swiftLanguageVersions` in package spec * Improve color lightness calculation --- Package.swift | 3 +- .../UIKit+Extensions/UIColor+Brightness.swift | 43 +++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Package.swift b/Package.swift index cb7ff1c88..ca2e6da04 100644 --- a/Package.swift +++ b/Package.swift @@ -56,5 +56,6 @@ let package = Package( .process("Resources") ] ) - ] + ], + swiftLanguageVersions: [.v5] ) diff --git a/Sources/ProcessOutCoreUI/Sources/Core/UIKit+Extensions/UIColor+Brightness.swift b/Sources/ProcessOutCoreUI/Sources/Core/UIKit+Extensions/UIColor+Brightness.swift index fad028905..524428c6c 100644 --- a/Sources/ProcessOutCoreUI/Sources/Core/UIKit+Extensions/UIColor+Brightness.swift +++ b/Sources/ProcessOutCoreUI/Sources/Core/UIKit+Extensions/UIColor+Brightness.swift @@ -9,20 +9,45 @@ import SwiftUI extension UIColor { + func isLight(threshold: CGFloat = 0.5) -> Bool? { + perceptualLightness.map { $0 > threshold } + } + + // MARK: - Private Methods + + /// Returns the relative luminance of this color in range [0, 1]. + /// /// - NOTE: Alpha is ignored - var brightness: CGFloat? { - let colorSpace = CGColorSpace(name: CGColorSpace.sRGB)! // swiftlint:disable:this force_unwrapping - let convertedColor = cgColor.converted( - to: colorSpace, intent: .defaultIntent, options: nil - ) + private var perceptualLightness: CGFloat? { + guard let luminance else { + return nil + } + if luminance <= 0.008856 { // Based on CIE standard + return luminance * 9.033 + } + return pow(luminance, 1 / 3) * 1.16 - 0.16 + } + + private var luminance: CGFloat? { + // swiftlint:disable:next force_unwrapping + let colorSpace = CGColorSpace(name: CGColorSpace.sRGB)! + let convertedColor = cgColor.converted(to: colorSpace, intent: .defaultIntent, options: nil) guard let components = convertedColor?.components, components.count >= 3 else { return nil } - // Calculation is based on this https://www.w3.org/WAI/ER/WD-AERT/#color-contrast - return (components[0] * 299 + components[1] * 587 + components[2] * 114) / 1000 + // swiftlint:disable identifier_name + let r = linearValue(ofGammaEncoded: components[0]) + let g = linearValue(ofGammaEncoded: components[1]) + let b = linearValue(ofGammaEncoded: components[2]) + // swiftlint:enable identifier_name + return 0.2126 * r + 0.7152 * g + 0.0722 * b } - func isLight(threshold: CGFloat = 0.5) -> Bool? { - brightness.map { $0 > threshold } + /// Convert a gamma encoded RGB to a linear value. + private func linearValue(ofGammaEncoded component: CGFloat) -> CGFloat { + if component <= 0.04045 { + return component / 12.92 + } + return pow((component + 0.055) / 1.055, 2.4) } }