计算互补,三元,四元和类似的颜色

时间:2016-05-05 16:35:55

标签: swift uicolor color-scheme color-wheel

我已经创建了swift函数,我将颜色值发送到并且想要返回三元组和四元组值。它有点工作,但我对颜色结果不满意。请问有人能帮我调整配方吗?

我关注的是几个来源,但与几个基于网络的在线配色方案相比,返回的颜色太亮或太饱和了。我知道这也是一个偏好问题,我有点像下面代码的结果,但在某些颜色的情况下,返回的一种颜色的结果太接近原始颜色的结果,所以它是隐约可见。它仅适用于少数几种颜色......

我正在使用此处的公式:

enter image description here

我的代码:

func getTriadColor(color: UIColor) -> (UIColor, UIColor){

    var hue : CGFloat = 0
    var saturation : CGFloat = 0
    var brightness : CGFloat = 0
    var alpha : CGFloat = 0

    let triadHue = CGFloat(color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha))

    let triadColor1 = UIColor(hue: (triadHue + 0.33) - 1.0, saturation: saturation, brightness: brightness, alpha: alpha)
    let triadColor2 = UIColor(hue: (triadHue + 0.66) - 1.0, saturation: saturation, brightness: brightness, alpha: alpha)


    return (triadColor1, triadColor2)

}

func getTetradColor(color: UIColor) -> (UIColor, UIColor, UIColor){

    var hue : CGFloat = 0
    var saturation : CGFloat = 0
    var brightness : CGFloat = 0
    var alpha : CGFloat = 0

    let tetradHue = CGFloat(color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha))

    let tetradColor1 = UIColor(hue: (tetradHue + 0.25) - 1.0, saturation: saturation, brightness: brightness, alpha: alpha)
    let tetradColor2 = UIColor(hue: (tetradHue + 0.5) - 1.0, saturation: saturation, brightness: brightness, alpha: alpha)
    let tetradColor3 = UIColor(hue: (tetradHue + 0.75) - 1.0, saturation: saturation, brightness: brightness, alpha: alpha)



    return (tetradColor1, tetradColor2, tetradColor3)
}

我还找到了很好的清洁代码来寻找补色,我对结果非常满意

func getComplementColor(color: UIColor) -> UIColor{

    let ciColor = CIColor(color: color)

    let compRed: CGFloat = 1.0 - ciColor.red
    let compGreen: CGFloat = 1.0 - ciColor.green
    let compBlue: CGFloat = 1.0 - ciColor.blue

    return UIColor(red: compRed, green: compGreen, blue: compBlue, alpha: 1.0)
}

1 个答案:

答案 0 :(得分:10)

屏幕截图中的公式不正确,因为它们指定使用绝对值函数而不是模数函数。也就是说,例如,您的屏幕截图定义了

  

H 1 = |(H 0 + 180°) - 360°|

但考虑一下输入H 0 = 90°:

  

H 1 = |(90°+ 180°) - 360°| = | 270° - 360°| = | -90°| = 90°

您是否认为H 0 = 90°的互补色调是H 1 = 90°,相同的色调?

正确的公式是

  

H 1 =(H 0 + 180°)mod 360°

其中“mod”是“modulo”的缩写,表示“除以后的余数”。换句话说,如果答案将超过360°,则减去360°。对于H 0 = 90°,这给出了H 1 = 270°的正确答案。

但是你的代码中甚至没有这个问题,因为你没有在代码中使用绝对值函数(或模数函数)。由于你没有做任何事情来保持你的色调值在0 ... 1的范围内,你的色调值小于零被剪裁为零,你的色调值高于1被剪裁为一个(零和一个均值为红色) )。

您的getComplementColor也不是“补色”的标准定义。

以下是正确的定义:

extension UIColor {

    var complement: UIColor {
        return self.withHueOffset(0.5)
    }

    var splitComplement0: UIColor {
        return self.withHueOffset(150 / 360)
    }

    var splitComplement1: UIColor {
        return self.withHueOffset(210 / 360)
    }

    var triadic0: UIColor {
        return self.withHueOffset(120 / 360)
    }

    var triadic1: UIColor {
        return self.withHueOffset(240 / 360)
    }

    var tetradic0: UIColor {
        return self.withHueOffset(0.25)
    }

    var tetradic1: UIColor {
        return self.complement
    }

    var tetradic2: UIColor {
        return self.withHueOffset(0.75)
    }

    var analagous0: UIColor {
        return self.withHueOffset(-1 / 12)
    }

    var analagous1: UIColor {
        return self.withHueOffset(1 / 12)
    }

    func withHueOffset(offset: CGFloat) -> UIColor {
        var h: CGFloat = 0
        var s: CGFloat = 0
        var b: CGFloat = 0
        var a: CGFloat = 0
        self.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
        return UIColor(hue: fmod(h + offset, 1), saturation: s, brightness: b, alpha: a)
    }
}

以下是补色的一些例子(原件在顶部,在下面互补):

complementary

以下是拆分补色(原件在上面):

split complementary

以下是三元颜色(原件在上面):

triadic

这是四色(原始的):

tetradic

以下是类似的颜色(中间原 ):

analagous

这是我用来生成这些图像的游乐场:

import XCPlayground
import UIKit

let view = UIView(frame: CGRectMake(0, 0, 320, 480))
view.backgroundColor = [#Color(colorLiteralRed: 0.9607843137254902, green: 0.9607843137254902, blue: 0.9607843137254902, alpha: 1)#]

let vStack = UIStackView(frame: view.bounds)
vStack.autoresizingMask = [ .FlexibleWidth, .FlexibleHeight ]
view.addSubview(vStack)
vStack.axis = .Vertical
vStack.distribution = .FillEqually
vStack.alignment = .Fill
vStack.spacing = 10

typealias ColorTransform = (UIColor) -> UIColor

func tile(color color: UIColor) -> UIView {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = color
    return view
}

func strip(transforms: [ColorTransform]) -> UIStackView {
    let strip = UIStackView()
    strip.translatesAutoresizingMaskIntoConstraints = false
    strip.axis = .Vertical
    strip.distribution = .FillEqually
    strip.alignment = .Fill
    strip.spacing = 0

    let hStacks = (0 ..< transforms.count).map { (i: Int) -> UIStackView in
        let stack = UIStackView()
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.axis = .Horizontal
        stack.distribution = .FillEqually
        stack.alignment = .Fill
        stack.spacing = 4
        strip.addArrangedSubview(stack)
        return stack
    }

    for h in 0 ..< 10 {
        let hue = CGFloat(h) / 10
        let color = UIColor(hue: hue, saturation: 1, brightness: 1, alpha: 1)
        for (i, transform) in transforms.enumerate() {
            hStacks[i].addArrangedSubview(tile(color: transform(color)))
        }
    }

    return strip
}

vStack.addArrangedSubview(strip([
    { $0 },
    { $0.complement }]))

vStack.addArrangedSubview(strip([
    { $0 },
    { $0.splitComplement0 },
    { $0.splitComplement1 }]))

vStack.addArrangedSubview(strip([
    { $0 },
    { $0.triadic0 },
    { $0.triadic1 }]))

vStack.addArrangedSubview(strip([
    { $0 },
    { $0.tetradic0 },
    { $0.tetradic1 },
    { $0.tetradic2 }]))

vStack.addArrangedSubview(strip([
    { $0.analagous0 },
    { $0 },
    { $0.analagous1 }]))

XCPlaygroundPage.currentPage.liveView = view