Extending Custom Filters - emcconville/cif GitHub Wiki
The cif utility can load & run custom Core Image Filters. Cif will search the following directories for bundle packages.
- Current user directory
$HOME/Library/Application Support/cif/Filters/ - System directory
/Library/Application Support/cif/Filters/ - Network Mount directory
/Network/Library/Application Support/cif/Filters/
To create a bundle, you would need to use Xcode to generate a new "Bundle" project, provide the basic Kernel script, Obj-C endpoints, and some very light meta info.
Creating a Kernel
// chromaKeyKernel.cikernel
// Classic Chroma-Key algorithm defined as...
// "alpha = K0 * blue - K1 * green + K2"
kernel vec4 chromaKey(sampler image, vec3 k)
{
__color pixel = sample(image, samplerCoord(image));
pixel.a = k.x * pixel.b - k.y * pixel.g + k.z;
return pixel;
}
Creating a CIFilter
// MyChromaKeyFilter.h
@import QuartzCore;
@interface MyChromeKeyFilter : CIFilter {
CIImage * inputImage;
CIVector * inputConstants;
}
@end
// MyChromaKeyFilter.m
#import "MyChromaKeyFilter.h"
static CIKernel * chromaKeyKernel = nil;
@implementation MyChromeKeyFilter
/**
~~ OPTIONAL ~~
Initialize class method communicates to CIF what this filter does.
The meta-information here populates the help/list display text.
*/
+(void) initialize
{
NSDictionary *attributes = @{
// Display name (should be the same as CIFilter class)
kCIAttributeFilterDisplayName: @"MyChromeKeyFilter",
kCIAttributeFilterName : @"MyChromeKeyFilter",
// Description
kCIAttributeDescription : @"Classic Chroma key algo"
};
// Register filter to populate CIF run-time
[CIFilter registerFilterName:@"MyChromeKeyFilter"
constructor:(id<CIFilterConstructor>)self
classAttributes:attributes];
}
/**
~~ REQUIRED ~~
Read the kernel script into memory before working with
class instance. (Better ways exists)
*/
-(id)init
{
if (chromaKeyKernel == nil) {
// Load kernel code
NSBundle * bundle = [NSBundle bundleForClass:[self class]];
NSString * path = [bundle pathForResource:@"chromaKeyKernel"
ofType:@"cikernel"];
NSString * code = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:nil];
NSArray * kernels = [CIKernel kernelsWithString:code];
chromaKeyKernel = kernels[0];
}
return [super init];
}
/**
~~ REQUIRED ~~
This method communicates what the behavior of the user input values should be.
Ensure all `kCIAttributeClass' values are standard
- CIColor
- CIImage
- CINumber
- CIVector
- NSData
- NSString
*/
- (NSDictionary *)customAttributes
{
return @{
kCIAttributeFilterName : @"MyChromeKeyFilter",
kCIInputImageKey : @{
kCIAttributeDescription : @"The image to apply chroma-key transparency"},
@"inputConstants" : @{
kCIAttributeDescription : @"Three K constants",
kCIAttributeDefault : [CIVector vectorWithX:1.0 Y:1.0 Z:1.0],
kCIAttributeClass : @"CIVector"}};
}
/**
~~ REQUIRED ~~
Collect/verify arguments, and execute kernel script.
*/
- (CIImage *)outputImage
{
CGRect extent = [inputImage extent];
CISampler * src = [CISampler samplerWithImage: inputImage];
CIImage * result = [self apply:chromaKeyKernel,
src,
inputConstants,
nil];
return [result imageByCroppingToRect:extent];
}
@end
Loading the CIFilter into the Bundle
If you only have a single filter, add the class name to the Bundle info as "Principal class". Cif assumes that each bundle's principal class is able to register any CIFilter. If your bundle has more than one filter, than create a simple generic "main" class to register other CIFilters.
// MyMain.m
#import "TomFilter.h"
#import "DickFilter.h"
#import "HarryFilter.h"
@implementation MyMain
+(void) initialize
{
[TomFilter class];
[DickFilter class];
[HarryFilter class];
}
@end
Build the bundle, and copy it to cif/Filters directory (listed above.) Run the following commands to test
cif list
Your filter should be present in the list of available filters.
cif list MyChromeKeyFilter
Expect to see the descriptive information given by MyChromeKeyFilter::initialize & MyChromeKeyFilter::customAttributes methods.
And finally, run your custom kernel
cif MyChromeKeyFilter -inputImage greenscreen.jpg -inputConstants 0.9,1.23,0.89 transparent.png