Is it possible to change my display to amber monochrome?

(This only addresses X11, not Wayland or other display management systems. Some of these techniques can be applied using other tools, e.g. the accessibility features of GNOME Shell.)

I can think of two ways of getting an amber display: insert a compositing plugin which fixes up all colours, and creating a colour profile which corrects all colours to an amber equivalent. Both of these probably involve more effort than they’re worth (apart from the learning side of things).

You can get a good approximation for primary colour displays by manipulating the per-channel gamma, as explained in sigvei’s answer; xcalib can also give access to this, and allows controlling the brightness and contrast directly as well as specifying the gamma value:

xcalib -blue 1.0 0 1.0 -red 1.0 0 1.0 -alter

results in a green display. Brightness and contrast are applied to the gamma ramps so xrandr will allow you to achieve the same results.

It’s possible to control the gamma ramps more finely still, but that won’t allow you to remap everything to amber colours anyway. You can “clamp” channels to certain ranges, so for example a bright red will have some green introduced and thus appear more amber-ish, but then dark reds would appear green...

The following code shows how to go about this (with no error-handling):

#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/extensions/xf86vmode.h>
#include <stdlib.h>

int main(int argc, char **argv) {
  Display * dpy = NULL;
  int screen = -1;
  u_int16_t * r_ramp = NULL, * g_ramp = NULL, * b_ramp = NULL;
  unsigned int ramp_size = 256;
  int r_tgt = 255, g_tgt = 191, b_tgt = 0;
  int i;

  dpy = XOpenDisplay(NULL);
  screen = DefaultScreen(dpy);

  /* Set up ramps */
  XF86VidModeGetGammaRampSize(dpy, screen, &ramp_size);
  r_ramp = (unsigned short *) calloc(ramp_size, sizeof(u_int16_t));
  g_ramp = (unsigned short *) calloc(ramp_size, sizeof(u_int16_t));
  b_ramp = (unsigned short *) calloc(ramp_size, sizeof(u_int16_t));
  for (i = 0; i < ramp_size; i++) {
    r_ramp[i] = r_tgt * 256 * i / ramp_size;
    g_ramp[i] = g_tgt * 256 * i / ramp_size;
    b_ramp[i] = b_tgt * 256 * i / ramp_size;
  }
  XF86VidModeSetGammaRamp(dpy, screen, ramp_size, r_ramp, g_ramp, b_ramp);
  XCloseDisplay(dpy);
}

(You’ll need -lX11 -lXxf86vm to link.)


xrandr --output $OUTPUT --gamma 1:0.01:0.01 gives you an almost monochrome red-on black.

The triplet of numbers are rgb values for the gamma correction, separated by :, in the range of 0-1. Replace 1:0.01:0.01 with 0.01:1:0.01 for green, and 0.01:0.01:1 for blue. It's hard to make any other color than these three basic ones. It becomes very much visible once you start letting more than one color through.

This method only works with dark/black backgrounds, because the gamma correction of bright white is just white.

Use xrandr -q to find the output ID to use for $OUTPUT; my laptop screen is LVDS-1, for instance.

Tags:

X11

Xrandr