Question

If I have an NSButton that uses a template image, how do I colorize it like Apple does in Xcode?

Was it helpful?

Solution

There is no API to colorize template images in buttons. In one of my latest applications I just wrote a small factory which created the colorized images on the fly from gray ones. I'm using core image filters which are processing the images incredible fast.

This is the main method of the factory which does the colorization:

- (NSImage *)imageNamed:(NSString *)name withOptions:(HcToolbarImageOptions)options
{
    NSString *key = [self keyForName:name withOptions:options];
    NSImage *image = _cache[key];
    if (!image) {
        NSImage *sourceImage = [NSImage imageNamed:name];
        NSAssert1(sourceImage != nil, @"Could not find any image named %@", name);
        if (options == 0) {
            image = sourceImage;
        } else {
            image = [NSImage imageWithSize:sourceImage.size flipped:NO drawingHandler:^BOOL(NSRect dstRect) {
                CIContext *context = [[NSGraphicsContext currentContext] CIContext];
                CGContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort];
                NSRect proposedRect = dstRect;
                CGImageRef cgImage = [sourceImage CGImageForProposedRect:&proposedRect context:[NSGraphicsContext currentContext] hints:nil];
                CIImage *result = [CIImage imageWithCGImage:cgImage];
                if (options & HcToolbarImage_Enabled) {
                    CIFilter *filter1 = [CIFilter filterWithName:@"CIGammaAdjust"];
                    [filter1 setDefaults];
                    [filter1 setValue:result forKey:kCIInputImageKey];
                    [filter1 setValue:@0.6 forKey:@"inputPower"];
                    result = [filter1 valueForKey:kCIOutputImageKey];
                    CIFilter *filter2 = [CIFilter filterWithName:@"CIColorMonochrome"];
                    [filter2 setDefaults];
                    [filter2 setValue:result forKey:kCIInputImageKey];
                    [filter2 setValue:@1.0f forKey:kCIInputIntensityKey];
                    [filter2 setValue:[CIColor colorWithRed:0.2 green:0.5 blue:1.0] forKey:kCIInputColorKey];
                    result = [filter2 valueForKey:kCIOutputImageKey];
                }
                CGRect extent = [result extent];
                CGImageRef finalImage = [context createCGImage:result fromRect:extent];
                if (options & HcToolbarImage_NotKeyWindow) {
                    CGContextSetAlpha(cgContext, 0.5);
                }
                CGContextDrawImage(cgContext, dstRect, finalImage);
                return YES;
            }];
        }
        [_cache setObject:image forKey:key];
    }
    return image;
}

The final images are cached in a NSMutableDictionary.

OTHER TIPS

Once again - if you're rolling your own tools like PaintCode can save you a bunch of time.

(And nope, still not affiliated with the PaintCode guys in any way. Just believing that tools and automation can save our precious development time)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top