6 Stimmen

Wie funktioniert die Farbumkehrung auf dem Bildschirm in OS X?

Dies ist, was die eingebaute Farbumkehrfunktion von OS X Ihren Bildschirm verwandeln kann:

Bildbeschreibung hier eingeben

Sie kann alle Farben invertieren, sie in Graustufen umwandeln, den Kontrast anpassen. Jetzt möchte ich meine eigene Implementierung erstellen und brauche daher den Rat von Fachleuten.

Die Unfähigkeit, den invertierten Bildschirm zu erfassen, ließ mich darüber nachdenken, dass die Umkehrung eine Art Anpassungsebene ist, die über allen Fenstern liegt und einfach nicht für die Interaktionsereignisse freigelegt ist. Ist das so? Wird dies über OpenGL-Bibliotheken erledigt?

Ich suche keine Hilfe beim eigentlichen Programmieren, sondern eher eine Design-/Herangehensweise zur Lösung des Problems. In meiner Ziel-App werde ich Ausgabefarbdiapasone definieren und Farbtransformationsregeln anwenden müssen (Eingabe => Ausgabe).

Vielen Dank im Voraus.

14voto

Nikolai Ruhe Punkte 80427

Die Art und Weise, wie Mac OS die Farbinversion durchführt, erfolgt (wahrscheinlich) durch die Verwendung von Quartz Display Services, um die Gamma-Tabelle der Grafikkarte zu ändern.

Grafikkarten haben zwei dieser Tabellen, um die Farbausgabe nach der Komposition in den endgültigen Frame-Buffer zu ändern. Eine davon kann von Anwendungen geändert werden, um die Art und Weise zu ändern, wie der Bildschirm einen beliebigen RGB-Wert zeigt.

Hier ist der Code zur Umkehrung der Anzeige:

//ApplicationServices enthält CoreGraphics
#import 

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

5voto

omz Punkte 52865

Zu einem gewissen Grad können Sie dies mit Core Image-Filtern tun. Dies ist jedoch eine private API, daher müssen Sie vorsichtig sein, da sich diese Dinge in zukünftigen OS X-Versionen ändern oder verschwinden könnten und Sie offensichtlich Ihre App nicht im App Store einreichen können. Ich denke nicht, dass so etwas mit öffentlichen APIs möglich ist.

Bearbeiten: Sehen Sie die Antwort von Nikolai Ruhe für eine bessere Methode, die öffentliche APIs verwendet. Mit Core Image-Filtern können Sie einige Dinge tun, die Sie mit einer Gamma-Tabelle nicht tun könnten (z.B. die Anwendung von Unschärfe-Filtern und ähnliches), daher lasse ich meine Antwort hier stehen.

Hier ist ein Beispiel, wie Sie das, was hinter einem Fenster liegt, invertieren können:

//Deklarationen, um Compilerwarnungen zu vermeiden (aufgrund privater 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; // unter dem Fenster
    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

(adaptiert von Steven Troughton Smiths Artikel hier)

screenshot

Der Effekt ist nicht perfekt, da aus irgendeinem Grund erforderlich ist, dass das Fenster eine Hintergrundfarbe hat, die nicht vollständig transparent ist, aber er ist ziemlich nah dran.

Um den gesamten Bildschirm zu beeinflussen, könnten Sie ein randloses Fenster erstellen, bei dem ignoresMouseEvents auf YES gesetzt ist (damit Sie hindurchklicken können).

Sie können mit anderen Filtern experimentieren, aber nicht alle funktionieren möglicherweise dafür. Es gibt einige Informationen zu den CGS...-Funktionen in diesem reverse-engineered Header: http://code.google.com/p/undocumented-goodness/source/browse/trunk/CoreGraphics/CGSPrivate.h

3voto

Ryan Schmitt Punkte 31

Der Weg, wie OS X selbst es tut, erfolgt durch eine Reihe von nicht dokumentierten CoreGraphics-API-Aufrufen. Ich glaube nicht, dass sie in irgendeiner offiziellen Header-Datei deklariert sind, aber Sie können die Prototypen einfach selbst deklarieren.

// clang -g -O2 -std=c11 -Wall -framework ApplicationServices

#include 
#include 

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

Es gibt ähnliche API-Aufrufe für andere Zugänglichkeitsfunktionen, wie z.B. Graustufen:

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

1voto

Dieser Artikel erklärt, wie ein anderer Benutzer seine Farben umgekehrt hat, jedoch wäre das kein Overlay, es würde Ihr Ziel immer noch erreichen. Obwohl dies in C# ist, wäre das vielleicht Ihr grundlegendes Konzept, da diese Ideen auch in Obj-C funktionieren können.

Im Grunde genommen sagt dieser Artikel, dass Sie Ihre RGB-Farbe in den HSV-Modus konvertieren und dann den Hue-Wert invertieren sollen. Um dies zu tun, müssen Sie den Hue-Wert um 360-Hue ändern und dann zurück in den RGB-Modus konvertieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X