Tinting a grayscale NSImage (or CIImage)
- (NSImage *)imageTintedWithColor:(NSColor *)tint
{
if (tint != nil) {
NSSize size = [self size];
NSRect bounds = { NSZeroPoint, size };
NSImage *tintedImage = [[NSImage alloc] initWithSize:size];
[tintedImage lockFocus];
CIFilter *colorGenerator = [CIFilter filterWithName:@"CIConstantColorGenerator"];
CIColor *color = [[[CIColor alloc] initWithColor:tint] autorelease];
[colorGenerator setValue:color forKey:@"inputColor"];
CIFilter *monochromeFilter = [CIFilter filterWithName:@"CIColorMonochrome"];
CIImage *baseImage = [CIImage imageWithData:[self TIFFRepresentation]];
[monochromeFilter setValue:baseImage forKey:@"inputImage"];
[monochromeFilter setValue:[CIColor colorWithRed:0.75 green:0.75 blue:0.75] forKey:@"inputColor"];
[monochromeFilter setValue:[NSNumber numberWithFloat:1.0] forKey:@"inputIntensity"];
CIFilter *compositingFilter = [CIFilter filterWithName:@"CIMultiplyCompositing"];
[compositingFilter setValue:[colorGenerator valueForKey:@"outputImage"] forKey:@"inputImage"];
[compositingFilter setValue:[monochromeFilter valueForKey:@"outputImage"] forKey:@"inputBackgroundImage"];
CIImage *outputImage = [compositingFilter valueForKey:@"outputImage"];
[outputImage drawAtPoint:NSZeroPoint
fromRect:bounds
operation:NSCompositeCopy
fraction:1.0];
[tintedImage unlockFocus];
return [tintedImage autorelease];
}
else {
return [[self copy] autorelease];
}
}
- (NSImage*)imageCroppedToRect:(NSRect)rect
{
NSPoint point = { -rect.origin.x, -rect.origin.y };
NSImage *croppedImage = [[NSImage alloc] initWithSize:rect.size];
[croppedImage lockFocus];
{
[self compositeToPoint:point operation:NSCompositeCopy];
}
[croppedImage unlockFocus];
return [croppedImage autorelease];
}
A Swift implementation of bluebamboo's answer:
func tintedImage(_ image: NSImage, tint: NSColor) -> NSImage {
guard let tinted = image.copy() as? NSImage else { return image }
tinted.lockFocus()
tint.set()
let imageRect = NSRect(origin: NSZeroPoint, size: image.size)
NSRectFillUsingOperation(imageRect, .sourceAtop)
tinted.unlockFocus()
return tinted
}
The above solution didn't work for me. But this much easier solution works great for me
- (NSImage *)imageTintedWithColor:(NSColor *)tint
{
NSImage *image = [self copy];
if (tint) {
[image lockFocus];
[tint set];
NSRect imageRect = {NSZeroPoint, [image size]};
NSRectFillUsingOperation(imageRect, NSCompositeSourceIn);
[image unlockFocus];
}
return image;
}