mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-21 15:57:31 +09:00
Dactyloidae iOS initial commit
This commit is contained in:
parent
daa6179d22
commit
7154a0497e
2123 changed files with 197052 additions and 0 deletions
278
mobile/ios/ThirdParty/UIImageColors.swift
vendored
Normal file
278
mobile/ios/ThirdParty/UIImageColors.swift
vendored
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
//
|
||||
// UIImageColors.swift
|
||||
// https://github.com/jathu/UIImageColors
|
||||
//
|
||||
// Created by Jathu Satkunarajah (@jathu) on 2015-06-11 - Toronto
|
||||
// Original Cocoa version by Panic Inc. - Portland
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public struct UIImageColors {
|
||||
public var background: UIColor!
|
||||
public var primary: UIColor!
|
||||
public var secondary: UIColor!
|
||||
public var detail: UIColor!
|
||||
}
|
||||
|
||||
class PCCountedColor {
|
||||
let color: UIColor
|
||||
let count: Int
|
||||
|
||||
init(color: UIColor, count: Int) {
|
||||
self.color = color
|
||||
self.count = count
|
||||
}
|
||||
}
|
||||
|
||||
extension CGColor {
|
||||
var components: [CGFloat] {
|
||||
get {
|
||||
var red = CGFloat()
|
||||
var green = CGFloat()
|
||||
var blue = CGFloat()
|
||||
var alpha = CGFloat()
|
||||
UIColor(cgColor: self).getRed(&red, green: &green, blue: &blue, alpha: &alpha)
|
||||
return [red,green,blue,alpha]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIColor {
|
||||
|
||||
var isDarkColor: Bool {
|
||||
let RGB = self.cgColor.components
|
||||
return (0.2126 * RGB[0] + 0.7152 * RGB[1] + 0.0722 * RGB[2]) < 0.5
|
||||
}
|
||||
|
||||
var isBlackOrWhite: Bool {
|
||||
let RGB = self.cgColor.components
|
||||
return (RGB[0] > 0.91 && RGB[1] > 0.91 && RGB[2] > 0.91) || (RGB[0] < 0.09 && RGB[1] < 0.09 && RGB[2] < 0.09)
|
||||
}
|
||||
|
||||
func isDistinct(compareColor: UIColor) -> Bool {
|
||||
let bg = self.cgColor.components
|
||||
let fg = compareColor.cgColor.components
|
||||
let threshold: CGFloat = 0.25
|
||||
|
||||
if fabs(bg[0] - fg[0]) > threshold || fabs(bg[1] - fg[1]) > threshold || fabs(bg[2] - fg[2]) > threshold {
|
||||
if fabs(bg[0] - bg[1]) < 0.03 && fabs(bg[0] - bg[2]) < 0.03 {
|
||||
if fabs(fg[0] - fg[1]) < 0.03 && fabs(fg[0] - fg[2]) < 0.03 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func colorWithMinimumSaturation(minSaturation: CGFloat) -> UIColor {
|
||||
var hue: CGFloat = 0.0
|
||||
var saturation: CGFloat = 0.0
|
||||
var brightness: CGFloat = 0.0
|
||||
var alpha: CGFloat = 0.0
|
||||
self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
|
||||
|
||||
if saturation < minSaturation {
|
||||
return UIColor(hue: hue, saturation: minSaturation, brightness: brightness, alpha: alpha)
|
||||
} else {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
func isContrastingColor(compareColor: UIColor) -> Bool {
|
||||
let bg = self.cgColor.components
|
||||
let fg = compareColor.cgColor.components
|
||||
|
||||
let bgLum = 0.2126 * bg[0] + 0.7152 * bg[1] + 0.0722 * bg[2]
|
||||
let fgLum = 0.2126 * fg[0] + 0.7152 * fg[1] + 0.0722 * fg[2]
|
||||
|
||||
let bgGreater = bgLum > fgLum
|
||||
let nom = bgGreater ? bgLum : fgLum
|
||||
let denom = bgGreater ? fgLum : bgLum
|
||||
let contrast = (nom + 0.05) / (denom + 0.05)
|
||||
return 1.6 < contrast
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension UIImage {
|
||||
private func resizeForUIImageColors(newSize: CGSize) -> UIImage {
|
||||
UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
|
||||
defer {
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
|
||||
guard let result = UIGraphicsGetImageFromCurrentImageContext() else {
|
||||
fatalError("UIImageColors.resizeForUIImageColors failed: UIGraphicsGetImageFromCurrentImageContext returned nil")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
Get `UIImageColors` from the image asynchronously (in background thread).
|
||||
Discussion: Use smaller sizes for better performance at the cost of quality colors. Use larger sizes for better color sampling and quality at the cost of performance.
|
||||
|
||||
- parameter scaleDownSize: Downscale size of image for sampling, if `CGSize.zero` is provided, the sample image is rescaled to a width of 250px and the aspect ratio height.
|
||||
- parameter completionHandler: `UIImageColors` for this image.
|
||||
*/
|
||||
public func getColors(scaleDownSize: CGSize = CGSize.zero, completionHandler: @escaping (UIImageColors) -> Void) {
|
||||
DispatchQueue.global().async {
|
||||
let result = self.getColors(scaleDownSize: scaleDownSize)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get `UIImageColors` from the image synchronously (in main thread).
|
||||
Discussion: Use smaller sizes for better performance at the cost of quality colors. Use larger sizes for better color sampling and quality at the cost of performance.
|
||||
|
||||
- parameter scaleDownSize: Downscale size of image for sampling, if `CGSize.zero` is provided, the sample image is rescaled to a width of 250px and the aspect ratio height.
|
||||
|
||||
- returns: `UIImageColors` for this image.
|
||||
*/
|
||||
public func getColors(scaleDownSize: CGSize = CGSize.zero) -> UIImageColors {
|
||||
|
||||
var scaleDownSize = scaleDownSize
|
||||
|
||||
if scaleDownSize == CGSize.zero {
|
||||
let ratio = self.size.width/self.size.height
|
||||
let r_width: CGFloat = 250
|
||||
scaleDownSize = CGSize(width: r_width, height: r_width/ratio)
|
||||
}
|
||||
|
||||
var result = UIImageColors()
|
||||
|
||||
let cgImage = self.resizeForUIImageColors(newSize: scaleDownSize).cgImage!
|
||||
let width: Int = cgImage.width
|
||||
let height: Int = cgImage.height
|
||||
|
||||
let blackColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
|
||||
let whiteColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
|
||||
|
||||
let randomColorsThreshold = Int(CGFloat(height)*0.01)
|
||||
let sortedColorComparator: Comparator = { (main, other) -> ComparisonResult in
|
||||
let m = main as! PCCountedColor, o = other as! PCCountedColor
|
||||
if m.count < o.count {
|
||||
return ComparisonResult.orderedDescending
|
||||
} else if m.count == o.count {
|
||||
return ComparisonResult.orderedSame
|
||||
} else {
|
||||
return ComparisonResult.orderedAscending
|
||||
}
|
||||
}
|
||||
|
||||
guard let data = CFDataGetBytePtr(cgImage.dataProvider!.data) else {
|
||||
fatalError("UIImageColors.getColors failed: could not get cgImage data")
|
||||
}
|
||||
|
||||
// Filter out and collect pixels from image
|
||||
let imageColors = NSCountedSet(capacity: width * height)
|
||||
|
||||
for x in 0..<width {
|
||||
for y in 0..<height {
|
||||
let pixel: Int = ((width * y) + x) * 4
|
||||
// Only consider pixels with 50% opacity or higher
|
||||
if 127 <= data[pixel+3] {
|
||||
imageColors.add(UIColor(
|
||||
red: CGFloat(data[pixel+2])/255,
|
||||
green: CGFloat(data[pixel+1])/255,
|
||||
blue: CGFloat(data[pixel])/255,
|
||||
alpha: 1.0
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get background color
|
||||
var enumerator = imageColors.objectEnumerator()
|
||||
var sortedColors = NSMutableArray(capacity: imageColors.count)
|
||||
while let kolor = enumerator.nextObject() as? UIColor {
|
||||
let colorCount = imageColors.count(for: kolor)
|
||||
if randomColorsThreshold < colorCount {
|
||||
sortedColors.add(PCCountedColor(color: kolor, count: colorCount))
|
||||
}
|
||||
}
|
||||
sortedColors.sort(comparator: sortedColorComparator)
|
||||
|
||||
var proposedEdgeColor: PCCountedColor
|
||||
if 0 < sortedColors.count {
|
||||
proposedEdgeColor = sortedColors.object(at: 0) as! PCCountedColor
|
||||
} else {
|
||||
proposedEdgeColor = PCCountedColor(color: blackColor, count: 1)
|
||||
}
|
||||
|
||||
if proposedEdgeColor.color.isBlackOrWhite && 0 < sortedColors.count {
|
||||
for i in 1..<sortedColors.count {
|
||||
let nextProposedEdgeColor = sortedColors.object(at: i) as! PCCountedColor
|
||||
if (CGFloat(nextProposedEdgeColor.count)/CGFloat(proposedEdgeColor.count)) > 0.3 {
|
||||
if !nextProposedEdgeColor.color.isBlackOrWhite {
|
||||
proposedEdgeColor = nextProposedEdgeColor
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
result.background = proposedEdgeColor.color
|
||||
|
||||
// Get foreground colors
|
||||
enumerator = imageColors.objectEnumerator()
|
||||
sortedColors.removeAllObjects()
|
||||
sortedColors = NSMutableArray(capacity: imageColors.count)
|
||||
let findDarkTextColor = !result.background.isDarkColor
|
||||
|
||||
while var kolor = enumerator.nextObject() as? UIColor {
|
||||
kolor = kolor.colorWithMinimumSaturation(minSaturation: 0.15)
|
||||
if kolor.isDarkColor == findDarkTextColor {
|
||||
let colorCount = imageColors.count(for: kolor)
|
||||
sortedColors.add(PCCountedColor(color: kolor, count: colorCount))
|
||||
}
|
||||
}
|
||||
sortedColors.sort(comparator: sortedColorComparator)
|
||||
|
||||
for curContainer in sortedColors {
|
||||
let kolor = (curContainer as! PCCountedColor).color
|
||||
|
||||
if result.primary == nil {
|
||||
if kolor.isContrastingColor(compareColor: result.background) {
|
||||
result.primary = kolor
|
||||
}
|
||||
} else if result.secondary == nil {
|
||||
if !result.primary.isDistinct(compareColor: kolor) || !kolor.isContrastingColor(compareColor: result.background) {
|
||||
continue
|
||||
}
|
||||
|
||||
result.secondary = kolor
|
||||
} else if result.detail == nil {
|
||||
if !result.secondary.isDistinct(compareColor: kolor) || !result.primary.isDistinct(compareColor: kolor) || !kolor.isContrastingColor(compareColor: result.background) {
|
||||
continue
|
||||
}
|
||||
|
||||
result.detail = kolor
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let isDarkBackgound = result.background.isDarkColor
|
||||
|
||||
if result.primary == nil {
|
||||
result.primary = isDarkBackgound ? whiteColor:blackColor
|
||||
}
|
||||
|
||||
if result.secondary == nil {
|
||||
result.secondary = isDarkBackgound ? whiteColor:blackColor
|
||||
}
|
||||
|
||||
if result.detail == nil {
|
||||
result.detail = isDarkBackgound ? whiteColor:blackColor
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue