Color adjustment option like Terminal.app
Terminal.app automatically adjusts text colors (only the 16 base colors) to the background color to offer better contrast. It would be cool if iTerm offered an option that mimicked that feature.
The interesting code is in the function adjustedColorWithRed:green:blue:alpha:withBackgroundColor:force:
of the TTView class in Terminal.app.
The first 4 arguments are the components of the color we are adjusting. Before obtaining the components the color was converted to the NSDeviceRGBColorspace
using colorUsingColorSpaceName
I tryed reversing the code of the function and this should be the result:
- (NSColor *)myColorWithRed:(double)red green:(double)green blue:(double)blue alpha:(double)alpha withBackgroundColor:(NSColor *)backgroundColor force:(BOOL)force {
ColorSyncProfileRef srcProfile = ColorSyncProfileCreateWithName(kColorSyncSRGBProfile);
ColorSyncProfileRef dstProfile = ColorSyncProfileCreateWithName(kColorSyncGenericLabProfile);
ColorSyncTransformRef transform[2];
for(int i = 0; i < 2; i++) {
const void *keys[] = {kColorSyncProfile, kColorSyncRenderingIntent, kColorSyncTransformTag};
const void *srcVals[] = {srcProfile, kColorSyncRenderingIntentPerceptual, kColorSyncTransformDeviceToPCS};
const void *dstVals[] = {dstProfile, kColorSyncRenderingIntentPerceptual, kColorSyncTransformPCSToDevice};
if (i) {
srcVals[0] = dstProfile;
dstVals[0] = srcProfile;
}
CFDictionaryRef srcDict = CFDictionaryCreate(
NULL,
(const void **)keys,
(const void **)srcVals,
3,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryRef dstDict = CFDictionaryCreate(
NULL,
(const void **)keys,
(const void **)dstVals,
3,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
const void* arrayVals[] = {srcDict, dstDict, NULL};
CFArrayRef profileSequence = CFArrayCreate(NULL, (const void **)arrayVals, 2, &kCFTypeArrayCallBacks);
transform[i] = ColorSyncTransformCreate(profileSequence, NULL);
if (srcDict) CFRelease (srcDict);
if (dstDict) CFRelease (dstDict);
if (profileSequence) CFRelease (profileSequence);
}
float dst1[3];
float src1[3] = {(float)red, (float)green, (float)blue};
ColorSyncTransformConvert(transform[0], 1, 1, dst1, 7, 0, 12, src1, 7, 0, 12, 0);
if(![[backgroundColor colorSpaceName] isEqualToString:@"NSDeviceRGBColorSpace"])
backgroundColor = [backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
float rB, gB, bB;
rB = (float)[backgroundColor redComponent];
gB = (float)[backgroundColor greenComponent];
bB = (float)[backgroundColor blueComponent];
float dst2[3];
float src2[3] = {rB, gB, bB};
float src3[3];
ColorSyncTransformConvert(transform[0], 1, 1, dst2, 7, 0, 12, src2, 7, 0, 12, 0);
if (force && ((sqrt((dst1[2] - dst2[2])*(dst1[2] - dst2[2]) + (dst1[1] - dst2[1])*(dst1[1] - dst2[1]) + (dst1[0] - dst2[0])*(dst1[0] - dst2[0])) < 0.2) || ((dst2[0] < 0.2) && (dst1[0] - dst2[0]) < 0.2))) {
src3[0] = fmod(dst1[0] + 0.5, 2.0);
}
else if (dst2[0] <= dst1[0]) {
src3[0] = (((dst1[0] * 0.8) + 0.2) * (1.0 - dst2[0])) + dst2[0];
} else {
src3[0] = ((dst1[0] * 0.8) + 0.2) * dst2[0];
}
float dst3[3];
src3[1] = dst1[1];
src3[2] = dst1[2];
ColorSyncTransformConvert(transform[1], 1, 1, dst3, 7, 0, 12, src3, 7, 0, 12, 0);
return [NSColor colorWithDeviceRed:(double)dst3[0] green:(double)dst3[1] blue:(double)dst3[2] alpha:alpha];
}
Terminal app also caches the two transform objects in the class so you don't have to create them every time. If the background color is nil
the function just returns the original color.