Tinting a grayscale NSImage (or CIImage)

后端 未结 8 1909
轮回少年
轮回少年 2021-01-30 09:02

I have a grayscale image which I want to use for drawing Cocoa controls. The image has various levels of gray. Where it is darkest, I want it to draw a specified tint color dark

相关标签:
8条回答
  • 2021-01-30 09:41

    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
    }
    
    0 讨论(0)
  • 2021-01-30 09:41

    I wanted to tint an image with a tint color that had alpha without seeing the original colors of the image show through. Here's how you can do that:

    extension NSImage {
        func tinting(with tintColor: NSColor) -> NSImage {
            guard let cgImage = self.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return self }
    
            return NSImage(size: size, flipped: false) { bounds in
                guard let context = NSGraphicsContext.current?.cgContext else { return false }
    
                tintColor.set()
                context.clip(to: bounds, mask: cgImage)
                context.fill(bounds)
    
                return true
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-30 09:43

    Swift version in form of Extension :

    extension NSImage {
        func tintedImageWithColor(color:NSColor) -> NSImage {
            let size        = self.size
            let imageBounds = NSMakeRect(0, 0, size.width, size.height)
            let copiedImage = self.copy() as! NSImage
    
            copiedImage.lockFocus()
            color.set()
            NSRectFillUsingOperation(imageBounds, .CompositeSourceIn)
            copiedImage.unlockFocus()
    
            return copiedImage
        }
    }
    
    0 讨论(0)
  • 2021-01-30 09:45
    - (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];
    }
    
    0 讨论(0)
  • 2021-01-30 09:46

    The CIMultiplyCompositing filter is definitely the way to do this. If it's crashing, can you post a stack trace? I use CIFilters heavily and don't have crashing issues.

    //assume inputImage is the greyscale CIImage you want to tint
    
    CIImage* outputImage = nil;
    
    //create some green
    CIFilter* greenGenerator = [CIFilter filterWithName:@"CIConstantColorGenerator"];
    CIColor* green = [CIColor colorWithRed:0.30 green:0.596 blue:0.172];
    [greenGenerator setValue:green forKey:@"inputColor"];
    CIImage* greenImage = [greenGenerator valueForKey:@"outputImage"];
    
    //apply a multiply filter
    CIFilter* filter = [CIFilter filterWithName:@"CIMultiplyCompositing"];
    [filter setValue:greenImage forKey:@"inputImage"];
    [filter setValue:inputImage forKey:@"inputBackgroundImage"];
    outputImage = [filter valueForKey:@"outputImage"];
    
    [outputImage drawAtPoint:NSZeroPoint fromRect:NSRectFromCGRect([outputImage extent]) operation:NSCompositeCopy fraction:1.0];
    
    0 讨论(0)
  • 2021-01-30 09:53

    Swift 5 version that also handles the alpha component of the tint color.

    I use this to support dark mode with multiple icon states by converting template icons to different colors and transparency levels. For example, you could pass NSColor(white: 0, alpha: 0.5) to get a dimmed version of an icon for light mode, and NSColor(white: 1, alpha: 0.5) to get a dimmed version for dark mode.

    func tintedImage(_ image: NSImage, color: NSColor) -> NSImage {
        let newImage = NSImage(size: image.size)
        newImage.lockFocus()
    
        // Draw with specified transparency
        let imageRect = NSRect(origin: .zero, size: image.size)
        image.draw(in: imageRect, from: imageRect, operation: .sourceOver, fraction: color.alphaComponent)
    
        // Tint with color
        color.withAlphaComponent(1).set()
        imageRect.fill(using: .sourceAtop)
    
        newImage.unlockFocus()
        return newImage
    }
    
    0 讨论(0)
提交回复
热议问题