How does on-screen color inversion work in OS X?

后端 未结 4 2078
感动是毒
感动是毒 2021-02-06 13:24

This is what OS X\'s built in color inversion feature can turn your screen into:

\"enter

4条回答
  •  旧时难觅i
    2021-02-06 13:54

    To some degree, you can do this with Core Image filters. However, this is private API, so you need to be careful because these things might change or go away in future OS X releases and you obviously cannot submit your app to the App Store. I don't think something like this is possible with public APIs.

    Edit: See Nikolai Ruhe's answer for a better method that uses public APIs. You can do some things with Core Image filters that you couldn't do with a gamma table (e.g. applying blur filters and the like), so I'll leave my answer here.

    Here's an example of how to invert what's behind a window:

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

    (adapted from Steven Troughton Smith's article here)

    screenshot

    The effect isn't perfect because for some reason it's necessary that the window has a background color that isn't fully transparent, but it's pretty close.

    To affect the whole screen, you could create a borderless window that has ignoresMouseEvents set to YES (so you can click through it).

    You can experiment with other filters, but not all of them may work for this. There's some info about the CGS... functions in this reverse-engineered header: http://code.google.com/p/undocumented-goodness/source/browse/trunk/CoreGraphics/CGSPrivate.h

提交回复
热议问题