【问题标题】:Is the method of using the | bitwise operator to mix two colours correct?是使用方法|按位运算符混合两种颜色正确吗?
【发布时间】:2016-04-01 03:45:21
【问题描述】:

我正在构建一个应用程序,允许用户选择两种颜色并查看混合它们的结果。例如,用户选择红色(#ff0000)和蓝色(#0000ff),结果为紫色(#ff00ff)。

我开始尝试在 UIColor 扩展中编写 3 个方法:

  • hexColorInt 转换为颜色
  • intValue 返回颜色的整数表示。即hexColor的反面
  • hexDescription 返回颜色的字符串表示形式,如“#ff00ff”

以下是实现,以防万一:

public static func hexColor(hex: Int32) -> UIColor {
    return UIColor.init(red: CGFloat((hex>>16)&0xFF) / 255.0, green: CGFloat((hex>>8)&0xFF) / 255.0, blue: CGFloat(hex&0xFF) / 255.0, alpha: 1.0)
}

public func intValue() -> Int {
    var hexString = self.hexDescription()
    hexString = hexString.substringFromIndex(hexString.startIndex.successor())
    return Int(hexString, radix: 16)!
}

public func hexDescription() -> String {
    var rF: CGFloat = 0,
    gF: CGFloat = 0,
    bF: CGFloat = 0,
    aF: CGFloat = 0
    self.getRed(&rF, green: &gF, blue: &bF, alpha: &aF)
    let r = Int(rF * 255.0)
    let g = Int(gF * 255.0)
    let b = Int(bF * 255.0)

    return "#" + String(format: "%02x%02x%02x", r, g, b)
}

然后我想到了如何真正混合颜色。我的第一个尝试是获取 HSV 值的平均值:

public func mixWith(color: UIColor) -> UIColor {
    var myHue: CGFloat = 0
    var mySat: CGFloat = 0
    var myVal: CGFloat = 0
    var otherHue: CGFloat = 0
    var otherSat: CGFloat = 0
    var otherVal: CGFloat = 0
    self.getHue(&myHue, saturation: &mySat, brightness: &myVal, alpha: nil)
    color.getHue(&otherHue, saturation: &otherSat, brightness: &otherVal, alpha: nil)

    let averageHue = (myHue + otherHue) / 2.0
    let averageSat = (mySat + otherSat) / 2.0
    let averageVal = (myVal + otherVal) / 2.0

    return UIColor(hue: averageHue, saturation: averageSat, brightness: averageVal, alpha: 1.0)
}

但这失败了。当我混合蓝色和黄色时,我得到 #00ff7f 但它应该是白色的。

然后我尝试获取 int 值的平均值:

public func mixWith2(color: UIColor) -> UIColor {
    let average = (self.intValue() + color.intValue()) / 2
    return UIColor.hexColor(Int32(average))
}

但同样,使用上述方法,蓝色与黄色的混合不是白色。

最后,我决定使用位运算符。我测试了 |、& 和 ^。令人惊讶的是,这会返回白色!

UIColor.hexColor(Int32(UIColor.blueColor().intValue() | 
    UIColor.yellowColor().intValue()))

这也是如此:

UIColor.hexColor(Int32(UIColor.blueColor().intValue() ^ 
    UIColor.yellowColor().intValue()))

我做了一些其他的测试,这个方法都通过了!

这是混合两种颜色的正确方法(始终给出正确的结果)吗?如果是,它是如何工作的?

【问题讨论】:

  • 我不是在问如何。我在问是否 |可用于混合颜色。 @ParthDabhi
  • 不,你不能使用 |结合两种颜色
  • @ParthDabhi 但是为什么UIColor.hexColor(Int32(UIColor.blueColor().intValue() | UIColor.yellowColor().intValue())) 返回白色?这是正确的结果!我也试过混合蓝色和红色,它会变成紫色!我只是幸运吗?我还更正了帖子中的一些内容。
  • 有许多可能的算法来“混合颜色”,具体取决于您尝试模拟的过程。您也许想要的是每个单独的 R/G/B 组件的总和或最大值。请注意,您的 mixWith2() 方法对单个整数而不是组件进行操作,这是不对的。

标签: swift colors bitwise-operators


【解决方案1】:

就像在 cmets 中一样,简短的回答是“不,你不能”,也许混合两种颜色的最简单方法是使用加权平均值:

extension UIColor {
    func blend(rhs:UIColor, midpoint left:CGFloat = 0.50) -> NSColor {
        let right = 1.0 - left

        var lr : CGFloat = 0
        var lg : CGFloat = 0
        var lb : CGFloat = 0
        var la : CGFloat = 0
        getRed(&lr, green: &lg, blue: &lb, alpha: &la)

        var rr : CGFloat = 0
        var rg : CGFloat = 0
        var rb : CGFloat = 0
        var ra : CGFloat = 0
        rhs.getRed(&rr, green: &rg, blue: &rb, alpha: &ra)

        return UIColor(
            red: lr * left + rr * right,
            green: lg * left + rg * right,
            blue: lb * left + rb * right,
            alpha: la * left + ra * right
        )
    }
}

【讨论】:

  • 谢谢!我在 cmets 中链接的一个答案中看到了这个解决方案。感谢您将其翻译成 swift。
  • NSColorUIColor ? – 请注意,使用此方法混合“蓝色”和“黄色”会得到 50% 的灰色,而不是问题中所需的白色。
  • 是的,这将饱和度减半(实际上是每个中点值减少),我正在整理一种我 认为 使用 HSV 可以正常工作的方法,它将保持饱和度. (并且结合蓝色和黄色应该得到绿色,而不是白色:)
  • 这取决于您使用的颜色模型,例如参见stackoverflow.com/a/4256156/1187415stackoverflow.com/questions/14819058/… 中的讨论。
  • trudat,现在是 0230,我累了,所以今晚就到此为止了 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-31
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 2017-04-09
相关资源
最近更新 更多