Created
October 11, 2020 22:35
-
-
Save JoshuaSullivan/dda5a79a0f72df7ba2c71f1004f2733b to your computer and use it in GitHub Desktop.
A Swift Playground that will enumerate the properties of all of the CoreImage filters.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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