我有一个结构,它以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

10-08 12:38