Skip to content

Instantly share code, notes, and snippets.

@JoshuaSullivan
Created October 11, 2020 22:35
Show Gist options
  • Save JoshuaSullivan/dda5a79a0f72df7ba2c71f1004f2733b to your computer and use it in GitHub Desktop.
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.
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