The Quick Fix

For like 95% of most cases, copy the following table into your Arduino sketch. You’ll see this same table a lot in our NeoPixel projects:

const uint8_t PROGMEM gamma8[] = {
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,
    1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,
    2,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,
    5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10,
   10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
   17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
   25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
   37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
   51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
   69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
   90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
  115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
  144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
  177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
  215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };

This table remaps linear input values (the numbers we’d like to use; e.g. 127 = half brightness) to nonlinear gamma-corrected output values (numbers producing the desired effect on the LED; e.g. 36 = half brightness).

Because the table is in program memory (PROGMEM in the declaration), it can’t be accessed directly…elements must be read using the pgm_read_byte() function, like this:

result = pgm_read_byte(&gamma8[input]);

Or, in the context of setting colors on an LED strip, it might resemble:

strip.setPixelColor(pixelNumber,
  pgm_read_byte(&gamma8[red]),
  pgm_read_byte(&gamma8[green]),
  pgm_read_byte(&gamma8[blue]));

That might get tedious after a while…you can write a wrapper function around setPixelColor() to make it easier, do all your gamma table lookups in that single place.

PROGMEM is a fantastic RAM-saver for Arduino sketches…if you’re not familiar, it’s explained on the Arduino web site, and our Memories of an Arduino guide also offers some insights.

Optional: you can move the gamma table to the bottom of your code (maybe you don’t want to look at it as the first thing every time you open a sketch) by adding this line near the top:

extern const uint8_t gamma8[];

The table isn’t really extern (this normally means some variable or data is located in another source file), but this lets us push it to the bottom while referring to it earlier in our code.

Gamma correction normally would use floating-point math, not something the Arduino excels at. This table lookup only takes about a microsecond, and despite its apparent size it’s really much smaller than invoking the equivalent floating-point math function (256 bytes vs. ~2KB of flash space).

This doesn’t give us ultimate control, but it’s adequate for the vast majority of cases. Orange will now look orange!

This guide was first published on Aug 29, 2014. It was last updated on Sep 24, 2018. This page (The Quick Fix) was last updated on Aug 19, 2016.