18

Given a start color and an end color, is it possible to algorithmically generate a range of colors between them? For example, given the light and dark shades of blue/gray at the start and end of the image below, how might I generate the intermediate shades?

enter image description here

One possible solution I am considering is to create a gradient from the two colors and then sample the color at equidistant points along that gradient. Is that likely to be the best approach?

3

6 Answers 6

24

Take a look at this answer. How to make a given color a bit darker or lighter?

Where you simply take the separated values of each RGB component and divide the values.

But we have one problem, there is not just one way to make a color transition.

enter image description here

The first aproach will give you the shortest route (1) but probably that route is not what you need.

This is also afected by the color model or logic. For example, in Lab* color model the Red and Green are complementary colors, so the short route on that model will be passing thru a neutral gray (3).

If you only need shades of a color, the other answer is a suitable one.

2
  • 5
    I like the graphic showing the different methods of interpolation Commented Jan 24, 2017 at 17:20
  • I guess this means that there has to be a way to codify the path strategy. Commented Mar 28, 2018 at 20:57
16

This is called color interpolation. It is what gradients do under the hood. You can do so using a variety of means and methods, and exactly how the results are interpolated depends on the method.

I commonly do this for web projects using JavaScript so that I can change colors dynamically, such as in this music visualizer. A JavaScript implementation that has a very straightforward method of linear interpolation using RGB, pulled from the example above, is as follows:

Live demo

// Returns a single rgb color interpolation between given rgb color
// based on the factor given; via https://codepen.io/njmcode/pen/axoyD?editors=0010
function interpolateColor(color1, color2, factor) {
    if (arguments.length < 3) { 
        factor = 0.5; 
    }
    var result = color1.slice();
    for (var i = 0; i < 3; i++) {
        result[i] = Math.round(result[i] + factor * (color2[i] - color1[i]));
    }
    return result;
};
// My function to interpolate between two colors completely, returning an array
function interpolateColors(color1, color2, steps) {
    var stepFactor = 1 / (steps - 1),
        interpolatedColorArray = [];

    color1 = color1.match(/\d+/g).map(Number);
    color2 = color2.match(/\d+/g).map(Number);

    for(var i = 0; i < steps; i++) {
        interpolatedColorArray.push(interpolateColor(color1, color2, stepFactor * i));
    }

    return interpolatedColorArray;
}

Which is used like so and returns an array of the interpolated colors:

var colorArray = interpolateColors("rgb(94, 79, 162)", "rgb(247, 148, 89)", 5);

You can also find PhotoShop (and likely other program) extensions for doing color interpolation.

However, you might want to check to make sure the method of interpolation is the same one that you desire, as you can use any function and color system to interpolate based on. For more about what I mean by that, see Rafael's answer. Also, here's one tool that generates gradients using a few different methods that illustrates the difference.

4
  • 2
    Zach... you are such a geek... that music visualizer is dam cool!
    – Rafael
    Commented Jan 24, 2017 at 16:13
  • @Rafael I made a couple others you may like as well :) Commented Jan 24, 2017 at 17:19
  • Thanks. Color Interpolation was what I needed. I found some Swift implementations here - stackoverflow.com/questions/22868182/uico… Commented Jan 24, 2017 at 19:31
  • 2
    The link above is broken, but the post can be found here for future readers: UIColor transition based on progress value Commented Jan 24, 2017 at 20:26
10

Use a blend in Illustrator in either RGB or CMYK:

  • create 2 shapes each with the start and end color (one gray and one black in this example, but choose whatever you need)
  • go to Object → Blend → Blend Options and type in how many Specified steps you need in between (20 in my example below)
  • select your two objects and choose Object → Blend → Make. This will generate the blend which you can then transform to individual objects via Object → Expand. Then you can see each intermediate object with it's own color code.

blending

0
5

This is an addition to the other answers.

When you interpolate colors in sRGB you have to consider that the RGB values are not linear in light intensity but linear in human perceived light intensity. This makes saving values easier, but for various color operations it is necessary to go to linear color space.

The human perception of light intensity is according to a power law, so with

linear = sRGB^2.2
sRGB = linear^(1/2.2)

can be used to transform between the two. This uses a gamma value of 2.2 which is the value for sRGB. For further information on this see this Wikipedia article.

A detailed analysis of this problem and examples of wrong implementations can be found here. One of which is a color gradient using linear and sRGB interpolation.

3
  • That's one method of interpolating sRGB values, but what a person should do depends on the effect they want Commented Jan 25, 2017 at 12:59
  • That's right, but interpolation in linear space is what happens with light in real life. So it is the most natural to do so.
    – henje
    Commented Jan 25, 2017 at 13:39
  • 1
    @ZachSaucier the number of times people have done interpolation or blending in sRGB out of specific intent is oh-so-tiny compared to the number of times people have done it out of ignorance or laziness (either thinking they are doing it in RGB, or thinking (rightly or not) that the difference is unimportant).
    – hobbs
    Commented Jan 26, 2017 at 9:47
1

Photoshop's gradient (or equivalently "Blend" in Ai) is already presented as a way to get a linear color transition between the starting and ending colors. How do we get something nonlinear (a curved transition path) without programming some scripting code?

One solution is to modify the gradient transition path by adjustment layers or blending modes or both. This really produces a continuous transform from the start color to the end color, if the modifying layers have a layer mask that is continuous and makes the affection = Zero at the start and in the end.

Here is a quite complex twist. Layer "Target alone" has the gradient and layer "Modifier" produces a continuous color shift by blending mode "Color" To make all twisty, the modifier itself is a gradient.

More twist is generated by an adjustment layer "Curves" that add contrast. It has the same layer mask as the Modifier, but that's not obligatory. Any mask is ok, if it's continuous and black at the start and in the end.

There exists some uncontinuous blending modes and curves that cause an abrupt jump. One of those is "Hue". Another possiblity to spoil the effect is "no change", a visible constant color area caused by clipping to all zero or all 255. I have not tested nor calculated, how much it in practice helps to use 48 bit/pixel RGB mode. Maybe not at all, because we still have only 24 bits/pixel onscreen.

Transition

1

I use some online tools to do it, like:

http://herethere.net/~samson/php/color_gradient/?cbegin=FF0000&cend=0000FF&steps=5 (my favorite practile one)

https://mistic100.github.io/tinygradient/ (kinda hard to get codes when are too may steps)

If you find another ones, you can comment here too, please! ;)

1
  • tinygradient is neat Commented Sep 25, 2023 at 16:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.