我有一个结构,它以rgba形式表示位图图像。该结构具有每个颜色通道(红色、蓝色和绿色)的属性。
我正在尝试建立一个图像过滤器来调整特定的颜色级别。此版本工作正常,但显然pixel.color属性是硬编码的。
func boostColor(inputColor: String) -> UIImage {
let avgColor = "avg" + inputColor
// let color = inputColor.lowercaseString // plan to use this to set the property
for y in 0..<self.inputRGBA.height {
for x in 0..<self.inputRGBA.width {
let index = y * self.inputRGBA.width + x
var pixel = self.inputRGBA.pixels[index]
// see how far this pixel's chosen color varies from the average
let colorDiff = Int(pixel.red) - Int(self.pixelColorAverages[avgColor]!)
// if less than average red,
if(colorDiff>0){
pixel.red = UInt8( max(0,min(255,Int(self.pixelColorAverages[avgColor]!) + colorDiff*100 ) ) )
// write the adjusted pixel back to the image object
self.inputRGBA.pixels[index] = pixel
}
}
}
// write the filtered RGBA image to a UIImage
return self.inputRGBA.toUIImage()!
}
此循环的函数接受字符串值“red”、“blue”或“green”。我要做的是替换
pixel.red
具有
pixel.[ONE OF THE INPUT COLORS]
谢谢!
(这是一个学术游乐场项目。我意识到我可能正在通过构建一个颜色过滤器来重新发明轮子。我感兴趣的不是滤色片本身,而是如何用swift解决这个属性问题。)
结构如下:
public struct Pixel {
public var value: UInt32
public var red: UInt8 {
get {
return UInt8(value & 0xFF)
}
set {
value = UInt32(newValue) | (value & 0xFFFFFF00)
}
}
public var green: UInt8 {
get {
return UInt8((value >> 8) & 0xFF)
}
set {
value = (UInt32(newValue) << 8) | (value & 0xFFFF00FF)
}
}
public var blue: UInt8 {
get {
return UInt8((value >> 16) & 0xFF)
}
set {
value = (UInt32(newValue) << 16) | (value & 0xFF00FFFF)
}
}
public var alpha: UInt8 {
get {
return UInt8((value >> 24) & 0xFF)
}
set {
value = (UInt32(newValue) << 24) | (value & 0x00FFFFFF)
}
}
}
最佳答案
使用reflecting
可以实现键值编码,但这非常不迅速。在您的情况下,这也是一个坏主意,因为有更强大和有用的选择。
我会去一个OptionSetType
因为只有固定数量的可能性(rgba)。一个enum
也可以,但一个OptionSetType
有额外的好处,成为一个“集”。因此,您可以选择以非常方便的方式更改RGB而不是A。
interesting read on OptionSetType
这是一个用于存储enum
的rawvalues的OptionSetType
。可单独使用。
public enum RGBAColor : Int, CustomStringConvertible {
case Red = 1, Green = 2, Blue = 4, Alpha = 8
public var description : String { // if you still want to have a String value for each color
var shift = 0
while (rawValue >> shift != 1) { shift++ }
return ["Red","Green","Blue","Alpha"][shift]
}
}
这是
OptionSetType
。我创建这些结构的片段,并在需要时复制/粘贴/修改它们。不需要重新发明轮子,因为它将永远是相同的模式。public struct RGBAColors : OptionSetType, CustomStringConvertible {
public let rawValue : Int
public init(rawValue:Int) { self.rawValue = rawValue}
private init(_ color:RGBAColor) { self.rawValue = color.rawValue }
static let Red = RGBAColors(RGBAColor.Red)
static let Green = RGBAColors(RGBAColor.Green)
static let Blue = RGBAColors(RGBAColor.Blue)
static let Alpha = RGBAColors(RGBAColor.Alpha)
public var description : String {
var result = ""
var shift = 0
while let currentcolor = RGBAColor(rawValue: 1 << shift++){
if self.contains(RGBAColors(currentcolor)){
result += (result.characters.count == 0) ? "\(currentcolor)" : ",\(currentcolor)"
}
}
return "[\(result)]"
}
}
现在,您可以向像素结构添加一个函数,该函数将基于
enum case
返回颜色值。您也可以选择将OptionSetType
直接传递给此函数。public struct Pixel {
...
public func getValueForColor(color:RGBAColor) -> UInt8 {
switch color {
case .Red : return self.red
case .Green : return self.green
case .Blue : return self.blue
case .Alpha : return self.alpha
}
}
}
这只是一个控制流功能。现在您可以根据需要更改的颜色执行不同的操作。(或对所有应用相同)
这也是选择
OptionSetType
的唯一原因,如果您不需要,只需选择一个enum
。由于OptionSetType
建立在enum
之上,您可以稍后添加它。func someFuncWithOptions(colors:RGBAColors) {
if colors.contains(.Red) {
someFunc(.Red)
}
if colors.contains(.Blue) {
someFunc(.Blue)
}
if colors.contains(.Green) {
someFunc(.Green)
}
if colors.contains(.Alpha) {
someFunc(.Alpha)
}
}
这将是您的实际功能
func someFunc(color:RGBAColor) {
// do something with pixel.getValueForColor(color)
print(color)
}
这将暴露在代码的其他部分。因此,所有这些的实际使用将非常简单。只需输入。
最好的是,如果您将所有这些更改为cmyk,编译器将警告您。键值编码永远不会产生警告,它只会崩溃。
因为它是一个“集合”,而不是按照定义一种颜色,所以您传递一组选项。或者你什么都不通过
someFuncWithOptions([.Red]) // red
someFuncWithOptions([.Green,.Red]) // red green
您还可以将方便的集合添加到
.SomeColor
中。这一个将是一组所有的RGB颜色,但没有阿尔法通道。static let RGB : RGBAColors = [.Red,.Green,.Blue]
someFuncWithOptions([.RGB]) // red blue green