着色灰度NSImage(或CIImage)

Pie*_*ard 28 cocoa objective-c core-image

我有一个灰度图像,我想用它来绘制Cocoa控件.图像具有不同级别的灰度.在最黑暗的地方,我希望它能画出最暗的指定色调.我希望它在源图像为白色时是透明的.

基本上,我想重现iPhone上UINavigationBar中看到的tintColor的行为.

到目前为止,我已经探索了几个选项:

  • 使用SourceOver合成在灰度图像上绘制色调颜色 - >这需要非不透明的色调 - >结果比期望的要暗得多

  • 使用CIMultiplyCompositing CIFilter为图像着色 - >我不能[CIImage drawAtPoint:fromRect:operation:fraction:]只绘制部分图像.同样适用于NSImage - >我偶尔会碰到一些我无法理解的崩溃

  • 将灰度图像转换为蒙版.即黑色应该是不透明的.白色应该是透明的.灰色应具有中间alpha值. - >这似乎是最好的解决方案 - >尽我所能,我无法做到这一点.

blu*_*boo 40

上述解决方案对我不起作用.但这个更容易的解决方案对我来说非常有用

- (NSImage *)imageTintedWithColor:(NSColor *)tint
{
    NSImage *image = [self copy];
    if (tint) {
        [image lockFocus];
        [tint set];
        NSRect imageRect = {NSZeroPoint, [image size]};
        NSRectFillUsingOperation(imageRect, NSCompositeSourceAtop);
        [image unlockFocus];
    }
    return image;
}
Run Code Online (Sandbox Code Playgroud)

  • 希望这证明对未来的某些人有用:如果您在使用此代码时遇到问题,请将复制的图像设置为不是模板,即在返回图像之前,[image setTemplate:NO].有点违反直觉,如果图像被设置为模板,它将完全忽略着色图像的代码,即使调试器预览将显示图像正确着色.我个人遇到了这个问题,因为我正在与iOS项目共享一个资产目录,其中图像集都被设置为模板. (2认同)

Jef*_*Hay 13

快速实现bluebamboo的答案:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您发布Swift翻译.我是在飞行中做的,所以我翻译了第一个答案.下次我可以向下滚动到Swift中.真棒! (2认同)
  • 对我来说,我必须使用“imageRect.fill(using:)” (2认同)

Pie*_*ard 8

- (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];
}
Run Code Online (Sandbox Code Playgroud)

  • 像我这样的n00bs确实需要花费不必要的时间来弄清楚如何使用这段代码:1-链接QuartzCore 2-导入它3-添加一个NSImage类别,里面有这个很棒的代码. (2认同)
  • 是的,我同意..这段代码摇滚......但不是含蓄地说_it是一个类别_会让很多人目瞪口呆.对于你所有的dumbies ..如果你不知道什么是类别..保存这个代码,找出一个类别是什么,然后回来使用它.∀Ⓛ∃✖ (2认同)

Sam*_*fes 7

我想用具有 alpha 的色调颜色为图像着色,而不会看到图像的原始颜色显示出来。您可以这样做:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)