As reference, I used the Wikipedia page about the BMP file format. The code is released under a BSD license and is available for download here. It can make 24-bit colour bitmaps. It also contains some functions to manipulate colours. Bitmaps are created by calling a write-bmp function.
It was an interesting experience to work with binary streams, and I learned a lot. The code's not that nice, and probably not that efficient either, but it does what I want, which is output pictures.
One of the arguments to write-bmp is used to determine the colour of each pixel, and can be either a list of lists, or a function of two arguments. Here's a call that produces a twelve colour diagonal rainbow:
(write-bmp (path "bitmaps/diagonal-rainbow3.bmp") 80 80
#'(lambda (row col) (rainbow12 (/ (+ row col) 2))))
The function rainbow12 selects a colour based on the floor of it's input mod 12. The above call produces*:
Here's a fun example using MathP:
(write-bmp (path "bitmaps/picture-perfect.bmp") 80 80
#M(fn(r c)
{applR = 2.5
inRad(x y rad) = (c-x)^2 + (r-y)^2 < rad^2
if inRad(15 65 6) yellow; inner sun
if inRad(15 65 8) orange; outer sun
if inRad(48 55 applR) || inRad(65 45 applR) || inRad(52 40 applR) red
if (r-50)^2+(c-55)^2<15^2 darkgreen
if r<20+3*cos(c/10) green; grass
if 50<c<60 && r<50 brown blue}))
It produces*:
But since computers are good at calculations, let's try something a little more intense (and random, and ... psychedelic):
(write-bmp (path "bitmaps/trigonometric2.bmp")
360 300
#'(lambda (row col)
(rainbow12
#M{(row^1.1 + 0.6*col + 35*cos(col/15)*sin(row/16)
+ 2 * sqrt((row-250)^2 + (col-200)^2)
+ 20 * cos((col-0.3*row)/70) * (2-sin(row/80))
+ 20 * (1-cos(0.7+col/25)) * cos(0.6-row/50))/15})))
Viola*:
I hope your eyes aren't bleeding too much after that one. ;-)
I've also implemented some anti-aliasing, here's are some anti-aliased pictures:
The last one above is an attempt at creating a 'world' map with things like seas (blue), beaches (yellow), vegetation (green) and mountains (brown and white). The jump from vegetation to beach is sharp, but the anti-aliasing smooths it nicely.