Skip to content

Instantly share code, notes, and snippets.

@strainer
Last active May 18, 2023 23:39
Show Gist options
  • Save strainer/ca20642e9a091634f685915bd6b90e51 to your computer and use it in GitHub Desktop.
Save strainer/ca20642e9a091634f685915bd6b90e51 to your computer and use it in GitHub Desktop.
theme inversion for scite
constexpr Scintilla::Colour InvertLight(Scintilla::Colour c) noexcept {
// Integer calcs done at x16 (0..4080 + 8) 0 => 0..15 255 => 4080..4095
int R = 8 + 16 * ( c & 0xffU );
int G = 8 + 16 * ( (c >>8) & 0xffU );
int B = 8 + 16 * ( (c >>16) & 0xffU );
const int rw = 18, gw = 35, bw = 11; // Brightness factors (compromised)
const int lumTrast = -64;
// `lumTrast` is like the contrast control of televisions,
// except it can go into negative to produce luminosity inversion.
// Value of 64 = 100% contrast, -64 = -100% contrast
const int addBright = 0; // Adjusts output brightness -1000 > 1000
const int sign = lumTrast<0 ? -1 : 1;
const int inLum = ( R*rw + G*gw + B*bw )/64 + 4 ; // lum of input. 8 to 4088
// Calculate target luminosity of rgb
long lumCalc = 2044 + ( (long)(inLum-2044)*lumTrast )/64;
// Skew very low or high targets to be less low or high
if (lumCalc>15 && lumCalc<4080) {
long apin = 50, bpin = 550; // drags 1% bright to 12%
if (lumCalc<apin) {
lumCalc = (bpin*lumCalc/apin);
} else lumCalc = bpin + (lumCalc-apin)*(4096-bpin)/(4096-apin);
apin = 4088-50, bpin = 4088-350; // drags 99% bright to 92%
if (lumCalc<apin) {
lumCalc = (bpin*lumCalc/apin);
} else lumCalc = bpin + (lumCalc-apin)*(4096-bpin)/(4096-apin);
}
lumCalc += (addBright*4088)/1000;
int outLum = (int)( lumCalc<8? 8 : lumCalc>4088? 4088 : lumCalc );
int mxc = R>G? R : G>B? G: B; // find max channel value
if(sign==-1 && mxc>3700 ) { // if max is near full
int avex = (R+G+B)*(mxc-3700)/(3000); // calculate saturation boost
R=R-avex ; G=G-avex ; B=B-avex;
int curLum = ( R*rw + G*gw + B*bw )/64; // re-estimate luminosity
R = (R*inLum)/curLum; // restore to inLum
G = (G*inLum)/curLum;
B = (B*inLum)/curLum;
}
int addmov = 0;
if (outLum > inLum) { // addmov descreases color when brightening
addmov = (outLum - inLum)*12/12; // move full way seems best
} else { // overshoot when darkening too boost color
addmov = outLum*2/3 - inLum;
}
R+=addmov; G+=addmov; B+=addmov;
if (outLum < inLum) {
int curLum = ( R*rw + G*gw + B*bw )/64 + 1;
R = (R*outLum)/curLum; // move rest of way by scaling R,G,B
G = (G*outLum)/curLum;
B = (B*outLum)/curLum;
}
// After gross Lum adjustments R,G,B values may be negative or overflow
const int un = 8 , ov = 4088; // Under and over flow limits
int rc = R<un ? R-un : R>ov ? R-ov : 0; // discern under-overflows
int gc = G<un ? G-un : G>ov ? G-ov : 0;
int bc = B<un ? B-un : B>ov ? B-ov : 0;
R-=rc; G-=gc; B-=bc; // remove them
rc = (rc*rw)/(gw+bw); // adjust carries by relative luminosity
gc = (gc*gw)/(rw+bw);
bc = (bc*bw)/(gw+rw);
R+=gc+bc; G+=rc+bc; B+=rc+gc; // redistribute carries
R-= R<un ? R-un : R>ov ? R-ov : 0; // remove any following excesses
G-= G<un ? G-un : G>ov ? G-ov : 0;
B-= B<un ? B-un : B>ov ? B-ov : 0;
return ColourRGB( R>>4, G>>4, B>>4 );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment