是使用|的方法按位运算符混合两种颜色是否正确?
Is the method of using the | bitwise operator to mix two colours correct?
我正在构建一个允许用户 select 两种颜色并查看混合它们的结果的应用程序。例如,用户selects红色(#ff0000)和蓝色(#0000ff)结果是紫色(#ff00ff)。
我开始尝试在 UIColor
扩展中编写 3 个方法:
hexColor
将 Int
转换为颜色
intValue
returns 颜色的整数表示。即 hexColor
的反转
hexDescription
returns颜色的字符串表示,如“#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))
}
但同样,使用上述方法,蓝色与黄色的混合不是白色。
最后,我决定使用位运算符。我测试了 |、& 和 ^。没想到,这个returns小白!
UIColor.hexColor(Int32(UIColor.blueColor().intValue() |
UIColor.yellowColor().intValue()))
还有这个:
UIColor.hexColor(Int32(UIColor.blueColor().intValue() ^
UIColor.yellowColor().intValue()))
我做了一些其他测试,这个方法全部通过了!
这是混合两种颜色的正确方法(始终给出正确的结果)吗?如果是,它是如何工作的?
简短的回答是 "no you can't" 如评论所述,也许混合两种颜色的最简单方法是使用加权平均值:
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
)
}
}
我正在构建一个允许用户 select 两种颜色并查看混合它们的结果的应用程序。例如,用户selects红色(#ff0000)和蓝色(#0000ff)结果是紫色(#ff00ff)。
我开始尝试在 UIColor
扩展中编写 3 个方法:
hexColor
将Int
转换为颜色intValue
returns 颜色的整数表示。即hexColor
的反转
hexDescription
returns颜色的字符串表示,如“#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))
}
但同样,使用上述方法,蓝色与黄色的混合不是白色。
最后,我决定使用位运算符。我测试了 |、& 和 ^。没想到,这个returns小白!
UIColor.hexColor(Int32(UIColor.blueColor().intValue() |
UIColor.yellowColor().intValue()))
还有这个:
UIColor.hexColor(Int32(UIColor.blueColor().intValue() ^
UIColor.yellowColor().intValue()))
我做了一些其他测试,这个方法全部通过了!
这是混合两种颜色的正确方法(始终给出正确的结果)吗?如果是,它是如何工作的?
简短的回答是 "no you can't" 如评论所述,也许混合两种颜色的最简单方法是使用加权平均值:
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
)
}
}