我有一个使用 NSImage 显示照片的应用程序 - 具体来说, - [NSImage drawInRect:fromRect:operation:fraction:] . 我想突出显示完全烧坏的照片区域(所有组件中的最大值,纯白色),使用红色等颜色,如某些数码相机和图像处理应用程序所做的那样,以帮助用户查看图像是否过度曝光,而且有多糟糕 .

我一直在摸索如何做到这一点 . 我考虑的选项:

  • 我可能会写一个核心图像过滤器来做它;没有任何内置过滤器可以查看任务 . 但这似乎有点矫枉过正;我一直在阅读文档,看起来相当复杂 . 大学习曲线 .

  • 我可以扫描图像的位图数据并根据需要进行修改 . 这很容易编码一个位图格式,但是大量的位图格式使它成为一个相当烦人的练习,速度在这里很重要,所以编写通用代码,使图像达到一些最大的通用格式并在其上工作位图对速度的影响太大了 .

  • 实际上,我已经在代码的较早点扫描图像(处理所有不同的位图格式),以生成图像的直方图数据 . 我可以非常轻松地添加代码,以便记住烧坏的像素供以后使用 . 我希望用一个alpha通道创建一个32位 NSBitmapImageRep ,所有这些只是为了这个目的,因为内存不是无限的,而且图像很大 . 但必须有办法以某种方式绘制给定颜色的1位掩码 .

在开始采用其中一种方法之前,我想我会看到这里是否有人有更好的想法 . 或者可能已经实施了CI过滤器?除了学习曲线,这似乎是我迄今为止所考虑的最佳方法 - 没有内存开销,也可能比其他选项更快 .

谢谢...

Ben Haller Stick软件


好的,我实现了自己的Core Image过滤器来做到这一点 . 虽然文档对于这些东西并不好,但并不像我预期的那么难 . doc示例都假设您正在使用ARC,因此如果您不使用ARC,请按照这些示例为您提供各种保留/释放错误 . CIFilterConstructor的东西也有些奇怪,这些内容并没有像记录的那样完整 . 但总的来说很容易 . CI很酷 . 对于任何可能发现它有用的人,我的代码如下:

Header:

    #import 

    @interface SSTintHighlightsFilter : CIFilter
    {
        CIImage *inputImage;
        CIColor *highlightColor;
    }
    @end

Implementation file:

    #import "SSTintHighlightsFilter.h"

    static CIKernel *tintHighlightsFilter = nil;

    @implementation SSTintHighlightsFilter

    + (void)initialize
    {
        [CIFilter registerFilterName:@"SSTintHighlightsFilter" constructor:(id )self
                     classAttributes:[NSDictionary dictionaryWithObjectsAndKeys:@"Tint Highlights", kCIAttributeFilterDisplayName, [NSArray arrayWithObjects:kCICategoryColorAdjustment, kCICategoryStillImage, nil], kCIAttributeFilterCategories, nil]];
    }

    + (CIFilter *)filterWithName:(NSString *)name
    {
        CIFilter *filter = [[self alloc] init];

        return [filter autorelease];
    }

    - (id)init
    {
        if (!tintHighlightsFilter)
        {
            NSBundle *bundle = [NSBundle bundleForClass:[self class]];
            NSString *code = [NSString stringWithContentsOfFile:[bundle pathForResource:@"tintHighlightsAndShadows" ofType:@"cikernel"] encoding:NSASCIIStringEncoding error:NULL];
            NSArray *kernels = [CIKernel kernelsWithString:code];

            tintHighlightsFilter = [[kernels objectAtIndex:0] retain];
        }

        return [super init];
    }

    - (NSDictionary *)customAttributes
    {
        NSDictionary *attrs = @{
              @"highlightColor" : @{ kCIAttributeClass : [CIColor class], kCIAttributeType : kCIAttributeTypeOpaqueColor }
        };

        return attrs;
    }

    - (CIImage *)outputImage
    {
        CISampler *src = [CISampler samplerWithImage:inputImage];

        return [self apply:tintHighlightsFilter
                 arguments:[NSArray arrayWithObjects:src, highlightColor, nil]
                   options:[NSDictionary dictionaryWithObjectsAndKeys:[src definition], kCIApplyOptionDefinition, nil]];
    }

    @end

tintHighlights.cikernel:

    kernel vec4 tintHighlights(sampler inputImage, __color highlightColor)
    {
        vec4 originalColor, tintedColor;
        float sum;

        // fetch the source pixel
        originalColor = sample(inputImage, samplerCoord(inputImage));

        // calculate the color component sum as a way of testing whether we are black or white
        sum = originalColor.r + originalColor.g + originalColor.b;

        // replace pixels that are white with the highlight color
        tintedColor = (sum > 2.99999999999999999999999) ? highlightColor : originalColor;

        // preserve alpha
        tintedColor.a = originalColor.a;

        return tintedColor;
    }

using the filter:

    + (NSImage *)showHighlightsInImage:(NSImage *)img dstRect:(NSRect)dstRect
    {
        NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
        NSRect dstRectForCGImage = dstRect;     // because the method below wants a pointer, and I don't trust it not to modify my rect...
        CGImageRef cgImage = [img CGImageForProposedRect:&dstRectForCGImage context:currentContext hints:nil];
        CIImage *inputImage = [[CIImage alloc] initWithCGImage:cgImage];

        [SSTintHighlightsFilter class];     // get my filter initialized

        CIFilter *highlightFilter = [CIFilter filterWithName:@"SSTintHighlightsFilter"];

        [highlightFilter setValue:inputImage forKey:@"inputImage"];
        [highlightFilter setValue:[CIColor colorWithRed:1.0 green:0.0 blue:0.0] forKey: @"highlightColor"];
        [inputImage release];

        CIImage *outputImage = [highlightFilter valueForKey:@"outputImage"];

        NSImage *resultImage = [[NSImage alloc] initWithSize:[img size]];
        [resultImage addRepresentation:[NSCIImageRep imageRepWithCIImage:outputImage]];

        return [resultImage autorelease];
    }

我不确定我是否完全可靠地处理alpha,还有预乘等问题,但除了可能出现的故障之外,它还能很好地工作 .