How to Generate Gradients and Textures

Some of you may have noticed the gradient background on this site now has a nice texture to it.

We often want to create gradients like that and, rather than having to open up a drawing tool every time, we use a Python library to generate PNG files based on a specification of the gradient and texture desired.

In a couple of older posts on my personal blog (Creating Gradients Programmatically in Python and HSL Gradients) I showed code I use for generating gradients in Python.

I've recently extended that code to support radial as well as linear gradients and to be able to add Gaussian noise to give a bit of texture.

Here is the famous blue gradient used by default in Pinax:

which was generated with the following code:

write_png("example5.png", 50, 80, gradient(LINEAR_Y, NO_NOISE, [
    (1.00, (0x00, 0x11, 0x33), (0x00, 0x55, 0x77)),
]))

Here is a glassy button background and the code used to create it. Notice the use of an HSV colour space to keep consistent hue and saturation and only vary the value.

write_png("example7.png", 200, 40, gradient(LINEAR_Y, NO_NOISE, [
    (0.5, HSV(0.55, 0.2, 0.40), HSV(0.55, 0.2, 0.54)),
    (1.0, HSV(0.55, 0.2, 0.47), HSV(0.55, 0.2, 0.61)),
]))

This is an example of a subtle radial gradient combined with a Gaussian noise texture.

write_png("example11.png", 480, 100,
    gradient(RADIAL(0.5, 0.0), GAUSSIAN(0.01),
    [(0.8, (0x22, 0x22, 0x22), (0x00, 0x00, 0x00))]
))

And finally here is a textured linear gradient inspired by Ryan Berg's on http://djangofriendly.com/.

write_png("example15.png", 200, 350, gradient(LINEAR_Y, GAUSSIAN(0.01),
    [(0.5, (0x01, 0x10, 0x09), (0x09, 0x2D, 0x1F))]
))

In practice, the non-radial, non-textured gradients only need to be one pixel thick. I've just made all these thicker so you can see the effect. With Gaussian noise textures, you want a thickness of at least 50 pixels (depending on the level of noise) otherwise the repetition is obvious. For example

where the number represents the actual width of the repeating background. Note that the noise is quite high in these examples (0.05) so even 50 isn't sufficient.

Obviously radial gradients need to be the full width as they aren't repeated.

The library code for generating all this (which is less than 80 lines of Python) is available from a git repository on GitHub.