A Swift Playground that will enumerate the properties of all of the CoreImage filters.
import Foundation | |
import CoreImage | |
struct FilterInput { | |
struct ValueRange { | |
let minValue: Float | |
let maxValue: Float | |
let sliderMin: Float? | |
let sliderMax: Float? | |
init?(dict: [String : AnyObject]) { | |
guard | |
let min = dict[kCIAttributeMin] as? Float, | |
let max = dict[kCIAttributeMax] as? Float | |
else { return nil } | |
self.minValue = min | |
self.maxValue = max | |
self.sliderMin = dict[kCIAttributeSliderMin] as? Float | |
self.sliderMax = dict[kCIAttributeSliderMax] as? Float | |
} | |
var description: String { | |
var parts: [String] = [] | |
parts.append("Min: \(minValue)") | |
parts.append("Max: \(maxValue)") | |
if let sMin = sliderMin, let sMax = sliderMax { | |
parts.append("Slider min: \(sMin)") | |
parts.append("Slider max: \(sMax)") | |
} | |
return parts.joined(separator: ", ") | |
} | |
} | |
enum InputType: String { | |
case angle = "CIAttributeTypeAngle" | |
case boolean = "CIAttributeTypeBoolean" | |
case color = "CIAttributeTypeColor" | |
case count = "CIAttributeTypeCount" | |
case distance = "CIAttributeTypeDistance" | |
case gradient = "CIAttributeTypeGradient" | |
case image = "CIAttributeTypeImage" | |
case integer = "CIAttributeTypeInteger" | |
case offset = "CIAttributeTypeOffset" | |
case opaquecolor = "CIAttributeTypeOpaqueColor" | |
case position = "CIAttributeTypePosition" | |
case position3 = "CIAttributeTypePosition3" | |
case rectangle = "CIAttributeTypeRectangle" | |
case scalar = "CIAttributeTypeScalar" | |
case time = "CIAttributeTypeTime" | |
case transform = "CIAttributeTypeTransform" | |
var description: String { return String(self.rawValue.dropFirst(15)) } | |
} | |
let name: String | |
let displayName: String | |
let inputClass: String | |
let inputType: InputType? | |
let description: String? | |
let defaultValue: AnyObject? | |
let valueRange: ValueRange? | |
init?(name: String, dict: [String : AnyObject]) { | |
guard | |
let inputClass = dict[kCIAttributeClass] as? String, | |
let displayName = dict[kCIAttributeDisplayName] as? String | |
else { return nil } | |
self.inputClass = inputClass | |
self.displayName = displayName | |
self.description = dict[kCIAttributeDescription] as? String | |
self.name = name | |
if let rawType = dict[kCIAttributeType] as? String { | |
self.inputType = InputType(rawValue: rawType) | |
} else { | |
self.inputType = nil | |
} | |
self.defaultValue = dict[kCIAttributeDefault] | |
self.valueRange = ValueRange(dict: dict) | |
} | |
func description(withIndent tabs: Int) -> String { | |
var lines: [String] = [] | |
let t2 = tabs + 1 | |
lines.append(tab(in: tabs) + displayName + " (\(name))") | |
lines.append(tab(in: t2) + "Class: " + inputClass) | |
if let type = inputType { | |
lines.append(tab(in: t2) + "Type: " + type.description) | |
} | |
if let desc = description { | |
lines.append(tab(in: t2) + "Description: " + desc) | |
} | |
if let def = defaultValue { | |
lines.append(tab(in: t2) + "Default: " + String(describing: def)) | |
} | |
if let range = valueRange { | |
lines.append(tab(in: t2) + "Range: " + range.description) | |
} | |
return lines.joined(separator: "\n") | |
} | |
} | |
let allFilterNames = CIFilter.filterNames(inCategory: kCICategoryBuiltIn) | |
let allFilters = allFilterNames.compactMap { CIFilter(name: $0) } | |
print("Core Image in iOS 14 has \(allFilterNames.count) filters.\n") | |
func equalLine(count: Int) -> String { | |
return (0..<count).map { _ in "=" }.joined(separator: "") | |
} | |
func tab(in count: Int) -> String { | |
return (0..<count).map { _ in "\t" }.joined() | |
} | |
func describe(filter f: CIFilter) -> String { | |
var lines: [String] = [] | |
// Fancy Title | |
let title: String = CIFilter.localizedName(forFilterName: f.name) ?? f.name | |
lines.append(equalLine(count: title.count)) | |
if | |
let versionString = f.attributes[kCIAttributeFilterAvailable_iOS] as? String, | |
let version = Float(versionString), | |
version >= 14.0 | |
{ | |
lines.append("\(title) 🌟") | |
} else { | |
lines.append(title) | |
} | |
lines.append(equalLine(count: title.count)) | |
lines.append("") | |
// Documentation | |
if let doc = f.attributes[kCIAttributeReferenceDocumentation] as? URL { | |
lines.append("[Documentation]") | |
lines.append("\t" + doc.absoluteString) | |
lines.append("") | |
} | |
// Availability | |
lines.append("[Availability]") | |
// iOS Availability | |
if let iosVer = f.attributes[kCIAttributeFilterAvailable_iOS] as? String { | |
lines.append("\t iOS: " + iosVer) | |
} else { | |
lines.append("\t iOS: ???") | |
} | |
// MacOS Availability | |
if let macVer = f.attributes[kCIAttributeFilterAvailable_Mac] as? String { | |
lines.append("\tmacOS: " + macVer) | |
} else { | |
lines.append("\tmacOS: ???") | |
} | |
lines.append("") | |
// Categories | |
if let rawCategories = f.attributes[kCIAttributeFilterCategories] as? [String] { | |
lines.append("[Categories]") | |
let categories = rawCategories | |
.map { CIFilter.localizedName(forCategory: $0) } | |
.joined(separator: ", ") | |
lines.append("\t\(categories)") | |
lines.append("") | |
} | |
// Inputs | |
lines.append("[Inputs]") | |
let inputs: [FilterInput] = f.inputKeys.compactMap { inputName in | |
guard let inputAttributes = f.attributes[inputName] as? [String: AnyObject] else { | |
return nil | |
} | |
return FilterInput(name: inputName, dict: inputAttributes) | |
} | |
inputs.map { $0.description(withIndent: 1) } | |
.forEach { lines.append($0 + "\n") } | |
lines.append("[Outputs]") | |
lines.append("\t" + f.outputKeys.joined(separator: ", ")) | |
return lines.joined(separator: "\n") | |
} | |
let descriptions = allFilters.map { describe(filter: $0) } | |
print(descriptions.joined(separator: "\n\n")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment