【问题标题】:How does on-screen color inversion work in OS X?屏幕颜色反转如何在 OS X 中工作?
【发布时间】:2012-12-19 06:48:47
【问题描述】:

这就是 OS X 内置的颜色反转功能可以将您的屏幕变成的样子:

它可以反转所有颜色,将它们变成灰度,调整对比度。现在我想构建自己的实现,因此需要专业人士的建议。

无法捕捉倒置屏幕让我认为倒置是一种调整层,位于所有窗口之上,根本不暴露于交互事件。是这样吗?是通过 OpenGL 库完成的吗?

我不研究实际的编码帮助,而是解决问题的设计/方法。在我的目标应用程序中,我需要定义输出颜色音调并应用颜色转换规则(输入 => 输出)。

提前致谢。

【问题讨论】:

    标签: objective-c cocoa colortransform


    【解决方案1】:

    OS X 本身的方式是通过一组未记录的 CoreGraphics API 调用。我认为它们没有在任何官方头文件中声明,但您始终可以自己声明原型。

    // clang -g -O2 -std=c11 -Wall -framework ApplicationServices
    
    #include <stdio.h>
    #include <ApplicationServices/ApplicationServices.h>
    
    CG_EXTERN bool CGDisplayUsesInvertedPolarity(void);
    CG_EXTERN void CGDisplaySetInvertedPolarity(bool invertedPolarity);
    
    int
    main(int argc, char** argv)
    {
        bool isInverted = CGDisplayUsesInvertedPolarity();
        printf("isInverted = %d\n", isInverted);
    
        sleep(2);
        CGDisplaySetInvertedPolarity(!isInverted);
        printf("Polarity is now: %d\n", CGDisplayUsesInvertedPolarity());
    
        sleep(2);
        CGDisplaySetInvertedPolarity(isInverted);
        printf("Polarity is now: %d\n", CGDisplayUsesInvertedPolarity());
    
        return 0;
    }
    

    其他辅助功能也有类似的 API 调用,例如灰度:

    CG_EXTERN bool CGDisplayUsesForceToGray(void);
    CG_EXTERN void CGDisplayForceToGray(bool forceToGray);
    

    【讨论】:

    • 有什么方法可以模拟 CGDisplayForceToGray 对 CGSetDisplayTransferByTable 的作用吗?
    【解决方案2】:

    Mac OS 进行颜色反转的方式(可能)是通过使用Quartz Display Services 来修改显卡的伽马表。

    显卡有两个这样的表,用于在合成到最终帧缓冲区后修改颜色输出。其中之一可以由应用程序修改,以改变屏幕显示任何 RGB 值的方式。

    下面是反转显示的代码:

    //ApplicationServices includes CoreGraphics
    #import <ApplicationServices/ApplicationServices.h>
    
    int main(int argc, const char * argv[])
    {
        CGGammaValue table[] = {1, 0};
        CGSetDisplayTransferByTable(CGMainDisplayID(), sizeof(table) / sizeof(table[0]), table, table, table);
        sleep(3);
        return 0;
    }
    

    【讨论】:

    • 非常有趣!我不知道这一点。
    • 我怎样才能使效果永久化(即使在此应用退出后颜色仍保持反转)?
    【解决方案3】:

    在某种程度上,您可以使用 Core Image 过滤器来做到这一点。但是,这是私有 API,因此您需要小心,因为这些东西可能会在未来的 OS X 版本中更改或消失,并且您显然无法将您的应用程序提交到 App Store。 我认为公共 API 不可能实现这样的事情。

    编辑:请参阅 Nikolai Ruhe 的回答,了解使用公共 API 的更好方法。你可以用 Core Image 滤镜做一些你不能用伽玛表做的事情(例如应用模糊滤镜等),所以我会在这里留下我的答案。

    这是一个如何反转窗口后面的示例:

    //Declarations to avoid compiler warnings (because of private APIs):
    typedef void * CGSConnection;
    typedef void * CGSWindowID;
    extern OSStatus CGSNewConnection(const void **attributes, CGSConnection * id);
    typedef void *CGSWindowFilterRef;
    extern CGError CGSNewCIFilterByName(CGSConnection cid, CFStringRef filterName, CGSWindowFilterRef *outFilter);
    extern CGError CGSAddWindowFilter(CGSConnection cid, CGSWindowID wid, CGSWindowFilterRef filter, int flags);
    extern CGError CGSSetCIFilterValuesFromDictionary(CGSConnection cid, CGSWindowFilterRef filter, CFDictionaryRef filterValues);
    
    @implementation AppDelegate
    
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
        [self.window setOpaque:NO];
        [self.window setAlphaValue:1.0];
        [self.window setBackgroundColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.1]];
        self.window.level = NSDockWindowLevel;
    
        CGSConnection thisConnection;
        CGSWindowFilterRef compositingFilter;
        int compositingType = 1; // under the window
        CGSNewConnection(NULL, &thisConnection);
        CGSNewCIFilterByName(thisConnection, CFSTR("CIColorInvert"), &compositingFilter);
        NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:3.0] forKey:@"inputRadius"];
        CGSSetCIFilterValuesFromDictionary(thisConnection, compositingFilter, (CFDictionaryRef)options);
        CGSAddWindowFilter(thisConnection, (CGSWindowID)[self.window windowNumber], compositingFilter, compositingType);    
    }
    
    @end
    

    (改编自Steven Troughton Smith's article here

    效果并不完美,因为出于某种原因,窗口必须具有不完全透明的背景颜色,但它非常接近。

    要影响整个屏幕,您可以创建一个无边框窗口,将ignoresMouseEvents 设置为YES(这样您就可以点击它)。

    您可以尝试使用其他过滤器,但并非所有过滤器都适用于此。在这个逆向工程的标头中有一些关于 CGS... 函数的信息:http://code.google.com/p/undocumented-goodness/source/browse/trunk/CoreGraphics/CGSPrivate.h

    【讨论】:

    • 谢谢。很有用。无论这是通过私有 API 还是公共 API 完成的,它仍然是一个 API,无论如何它都是基于 C(Objective-C)的。然后我想我会寻求进入兔子洞。额外感谢文章链接。
    【解决方案4】:

    This 文章解释了另一个用户如何反转他的颜色,但这不会是叠加,它仍然可以实现您的目标。虽然这是在 C# 中,这可能是您的基本前提,因为这些相同的想法可以在 Obj-c 中工作。

    基本上这篇文章说要在 HSV 模式下转换 RGB 颜色,然后反转色调值。为此,您必须将 Hue 更改为 360-Hue,然后再转换回 RGB 模式。

    【讨论】:

    • 感谢您的链接。然而,这并不是我想要的。
    • @AleksandrMakov 好的,我会看看还有什么。
    • 虽然这可能在技术上回答问题,it would be preferable 供您在此处总结链接材料。否则,答案可能会因链接失效而失去其用处。
    • @JoshCaswell KK,我会解决这个问题。更好?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-11
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多