Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 为灰度NSImage(或CIImage)着色_Objective C_Cocoa_Core Image - Fatal编程技术网

Objective c 为灰度NSImage(或CIImage)着色

Objective c 为灰度NSImage(或CIImage)着色,objective-c,cocoa,core-image,Objective C,Cocoa,Core Image,我有一个灰度图像,我想用于绘制控件。图像具有不同级别的灰度。在最暗的地方,我希望它绘制最暗的指定色调。我希望它是透明的地方,源图像是白色的 基本上,我想重现iPhone上UINavigationBar中的tintColor行为 到目前为止,我已经探索了几个选项: 使用SourceOver composition在灰度图像上绘制着色颜色 ->这需要非不透明的着色颜色 ->结果比预期的要暗得多 使用CIMultiplycomposition CIFilter为图像着色 ->我无法[CIImage

我有一个灰度图像,我想用于绘制控件。图像具有不同级别的灰度。在最暗的地方,我希望它绘制最暗的指定色调。我希望它是透明的地方,源图像是白色的

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

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

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

  • 使用CIMultiplycomposition CIFilter为图像着色 ->我无法[CIImage drawAtPoint:fromRect:operation:fraction:]仅绘制图像的一部分。同样适用于NSImage ->我偶尔会撞车,这是我无法理解的

  • 将灰度图像转换为遮罩。也就是说,黑色应该是不透明的。白色应该是透明的。灰色应该有中间的alpha值。 ->这似乎是最好的解决办法 ->尽管我尽了最大努力,但我无法做到这一点


CIMultiplycomposition过滤器无疑是实现这一点的方法。如果它崩溃了,你能发布堆栈跟踪吗?我大量使用CIFilters,没有崩溃问题

//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];

上述解决方案对我不起作用。但这个简单得多的解决方案对我来说非常有效

- (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;
}

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
}

对于更精细的粒度,您可以使用多项式颜色方法,使用我在下面建议的方法:

扩展形式的Swift版本:

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
    }
}

我想用带有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
        }
    }
}

Swift 5版本,也处理色调颜色的alpha分量

通过将模板图标转换为不同的颜色和透明度级别,我使用它来支持具有多个图标状态的暗模式。例如,您可以传递
NSColor(白色:0,alpha:0.5)
以获得灯光模式下图标的变暗版本,传递
NSColor(白色:1,alpha:0.5)
以获得暗模式下的变暗版本

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
}


我决定分两个连续步骤进行着色和裁剪。只要我画出整个图像,cimultiplycomposition就可以很好地工作。我画了一个NSImage,然后我画了一部分更小的图片。你真的需要使用“CIConstantColorGenerator”吗?为什么不使用CIImage*greenImage=[CIImage imageWithColor:green]?是的,你可以。这种方法是在10.5版本才引入的,早在2009年我写下这个答案时,Tiger仍然被广泛使用。最后一行代码的目的是什么?在那之前,输出图像不是已经在生产线上生成了吗?它只是一个如何绘制
CIImage
的示例,实际上并不需要获取图像本身。正如您所指出的,您已经拥有上一行代码中的实际图像。像我这样的N00B真的需要花费不必要的时间来了解如何使用此代码:1-链接QuartzCore 2-导入它3-添加一个NSImage类别,其中包含这段很棒的代码。是的,我同意。。这段代码触动了……但如果不含蓄地说它是一个类别,会让很多人目瞪口呆。为了你们这些笨蛋。。如果你不知道什么是类别。。保存此代码,找出类别,然后回来使用它。∀Ⓛ∃✖虽然我理解代码,但似乎无法从中得到任何结果。我给它一个全黑图标和透明背景的tiff图像,并尝试用白色或黑色着色。上面的代码将把灰色像素转换成与着色颜色一样暗的着色像素。如果你的源图像是黑色的,结果也会是黑色的。我没有向GitHub发布上述代码的稍微更新版本:谢谢你发布Swift翻译。我在飞行中做了,所以我翻译了第一个答案。下一次我可以在这里向下滚动,然后在Swift中获取它。令人惊叹的!谢谢,这对我很有吸引力。只是一个提示快速提示(至少在macOS上)如果您使用的图像设置为渲染为“模板”,则它不起作用,请选择渲染为“默认”。对于我来说,我必须使用
imageRect.fill(使用:)
您需要使用
.sourceIn
才能正确着色,特别是如果您试图用较淡的色调替换原始颜色,希望这对将来的人有用:如果您在使此代码正常工作时遇到问题,请在返回图像之前将复制的图像设置为非模板ie,[图像设置模板:否]。与直觉相反,如果将图像设置为模板,它将完全忽略为图像着色的代码,即使调试器预览将向您显示图像已正确着色。我个人遇到了这个问题,因为我正在与一个iOS项目共享一个资产目录,其中图像集都设置为模板。一切都正常,但我必须关闭资产目录中的模板图像才能正常工作。非常重要的一点,谢谢!这是可行的,但它使我的图像模糊。有人有类似的问题吗?根据新的Swift API指南,您可以将定义更改为:
func-tinted(color:NSColor)->NSImage
谢谢,我将检查代码是否在Swift 3.0下编译并更新答案。
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
}