Similar to the images on allrgb.com, make images where each pixel is a unique color (no color is used twice and no color is missing).

Give a program that generates such an image, along with a screenshot or file of the output (upload as PNG).

  • Create the image purely algorithmically.
  • Image must be 256×128 (or grid that can be screenshot and saved at 256×128)
  • Use all 15-bit colors*
  • No external input allowed (also no web queries, URLs or databases)
  • No embedded images allowed (source code which is an image is fine, e.g. Piet)
  • Dithering is allowed
  • This is not a short code contest, although it might win you votes.
  • If you're really up for a challenge, do 512×512, 2048×1024 or 4096×4096 (in increments of 3 bits).

Scoring is by vote. Vote for the most beautiful images made by the most elegant code and/or interesting algorithm.

Two-step algorithms, where you first generate a nice image and then fit all pixels to one of the available colors, are of course allowed, but won't win you elegance points.

* 15-bit colors are the 32768 colors that can be made by mixing 32 reds, 32 greens, and 32 blues, all in equidistant steps and equal ranges. Example: in 24 bits images (8 bit per channel), the range per channel is 0..255 (or 0..224), so divide it up into 32 equally spaced shades.

To be very clear, the array of image pixels should be a permutation, because all possible images have the same colors, just at different pixels locations. I'll give a trivial permutation here, which isn't beautiful at all:

Java 7

import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;

public class FifteenBitColors {
    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(256, 128, BufferedImage.TYPE_INT_RGB);

        // Generate algorithmically.
        for (int i = 0; i < 32768; i++) {
            int x = i & 255;
            int y = i / 256;
            int r = i << 3 & 0xF8;
            int g = i >> 2 & 0xF8;
            int b = i >> 7 & 0xF8;
            img.setRGB(x, y, (r << 8 | g) << 8 | b);
        }

        // Save.
        try (OutputStream out = new BufferedOutputStream(new FileOutputStream("RGB15.png"))) {
            ImageIO.write(img, "png", out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

enter image description here

Winner

Because the 7 days are over, I'm declaring a winner

However, by no means, think this is over. I, and all readers, always welcome more awesome designs. Don't stop creating.

Winner: fejesjoco with 231 votes

  • 8
    When you say "Dithering is allowed", what do you mean? Is this an exception to the rule "each pixel is a unique color"? If not, what are you allowing which was otherwise forbidden? – Peter Taylor Feb 25 '14 at 22:02
  • 1
    It means you can place colors in a pattern, so when viewed with the eye, they blend into a different color. For example, see the image "clearly all RGB" on the allRGB page, and many others there. – Mark Jeronimus Feb 26 '14 at 6:42
  • 8
    I actually find your trivial permutation example to be quite pleasing to the eye. – Jason C Feb 27 '14 at 0:48
  • 2
    @Zom-B Man, I freakin' love this post. Thanks! – Jason C Feb 27 '14 at 17:26
  • 7
    Beautiful results/answers! – EthanB Feb 28 '14 at 3:37

47 Answers 47

Not the most elegant code, but interesting on two counts: Computing the number of colors from the dimensions (as long as the product of dimensions is a power of two), and doing trippy color space stuff:

void Main()
{
    var width = 256;
    var height = 128;
    var colorCount = Math.Log(width*height,2);
    var bitsPerChannel = colorCount / 3;
    var channelValues = Math.Pow(2,bitsPerChannel);
    var channelStep = (int)(256/channelValues);

    var colors = new List<Color>();

    var m1 = new double[,] {{0.6068909,0.1735011,0.2003480},{0.2989164,0.5865990,0.1144845},{0.00,0.0660957,1.1162243}};
    for(var r=0;r<255;r+=channelStep)
    for(var g=0;g<255;g+=channelStep)
    for(var b=0;b<255;b+=channelStep)   
    {
        colors.Add(Color.FromArgb(0,r,g,b));
    }
    var sortedColors = colors.Select((c,i)=>
                            ToLookupTuple(MatrixProduct(m1,new[]{c.R/255d,c.G/255d,c.B/255d}),i))
                            .Select(t=>new
                                            {
                                                x = (t.Item1==0 && t.Item2==0 && t.Item3==0) ? 0 : t.Item1/(t.Item1+t.Item2+t.Item3),
                                                y = (t.Item1==0 && t.Item2==0 && t.Item3==0) ? 0 :t.Item2/(t.Item1+t.Item2+t.Item3),
                                                z = (t.Item1==0 && t.Item2==0 && t.Item3==0) ? 0 :t.Item3/(t.Item1+t.Item2+t.Item3),
                                                Y = t.Item2,
                                                i = t.Item4
                                            })
                            .OrderBy(t=>t.x).Select(t=>t.i).ToList();
    if(sortedColors.Count != (width*height))
    {
        throw new Exception(string.Format("Some colors fell on the floor: {0}/{1}",sortedColors.Count,(width*height)));
    }
    using(var bmp = new Bitmap(width,height,PixelFormat.Format24bppRgb))
    {
        for(var i=0;i<colors.Count;i++)
        {
            var y = i % height;
            var x = i / height;

            bmp.SetPixel(x,y,colors[sortedColors[i]]);
        }
        //bmp.Dump(); //For LINQPad use
        bmp.Save("output.png");
    }
}
static Tuple<double,double,double,int>ToLookupTuple(double[] t, int index)
{
    return new Tuple<double,double,double,int>(t[0],t[1],t[2],index);
}

public static double[] MatrixProduct(double[,] matrixA,
    double[] vectorB)
{
    double[] result=new double[3];
    for (int i=0; i<3; ++i) // each row of A
        for (int k=0; k<3; ++k)
            result[i]+=matrixA[i,k]*vectorB[k];
    return result;
}

Some interesting variations can be had just by changing the OrderBy clause:

x:

enter image description here

y:

enter image description here

z:

enter image description here

Y:

enter image description here

I wish I could figure out what was causing the odd lines in the first three

  • 2
    Those odd lines are probably the bias of some sort or look-up method (binary search / quicksort?) – Mark Jeronimus Feb 26 '14 at 21:55
  • I actually really like the lines here. – Jason C Feb 27 '14 at 22:53

Go

Here's my take, using Golang and its default packages to generate a GIF containing all the colors:

package main

import (
    "image"
    "image/color"
    "image/gif"
    "os"
)

func main() {
    var idx uint8
    frames := make([]*image.Paletted, 256)
    delay := make([]int, 256)
    for x := 0; x < 256; x++ {
        pal := make(color.Palette, 129)
        pal[0] = color.RGBA{0, 0, 0, 0}
        idx = 1
        for y := 0; y < 128; y++ {
            pal[idx] = color.RGBA{uint8(x%32) * 8, uint8(y%32) * 8, uint8(x/32+(y/32*8)) * 8, 255}
            idx++
        }
        img := image.NewPaletted(image.Rect(0, 0, 256, 128), pal)
        idx = 1
        for y := 0; y < 128; y++ {
            img.SetColorIndex(x, y, idx)
            idx++
        }
        frames[x] = img
        delay[x] = 1
    }
    jif := gif.GIF{frames, delay, 1}
    file, err := os.Create("EveryColor.gif")
    if err != nil {
        panic(err)
    }
    err = gif.EncodeAll(file, &jif)
    if err != nil {
        panic(err)
    }
    file.Close()

}

And the output:

animated gif containing 2^15 colors

Not pretty like many of the other answers, but it uses the GIF format in an interesting way.

I used to make these infinite recursive sorters when I was learning to write code, very rewarding to program so little. It will eventually converge around something like below for random colors - but it has the very unique property of continuously walking.

Converges around something like this for random colors.

If you're brave enough to run the 4096x4096 version in your browser with each pixel a different color: god speed to that one poor CPU core handling the JavaScript thread. I am in no way responsible for that whirring fan noise you now hear, or the soon to follow laptop fire.

Source (or here as a gist https://gist.github.com/adrianseeley/9516453):

<canvas id="canvas" width="256", height="256"></canvas>
<script type="text/javascript">
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var imgdata = ctx.createImageData(canvas.width, canvas.height);
    function set_pixel (x, y, r, g, b) { var index = (x + y * imgdata.width) * 4; imgdata.data[index + 0] = r; imgdata.data[index + 1] = g; imgdata.data[index + 2] = b; imgdata.data[index + 3] = 255; };
    function swap_pixels (x1, y1, x2, y2) { var p1 = get_pixel(x1, y1); var p2 = get_pixel(x2, y2); set_pixel(x1, y1, p2[0], p2[1], p2[2]); set_pixel(x2, y2, p1[0], p1[1], p1[2]); };
    function get_pixel (x, y) { var index = (x + y * imgdata.width) * 4; return [imgdata.data[index + 0], imgdata.data[index + 1], imgdata.data[index + 2]]; };
    function draw () { ctx.putImageData(imgdata, 0, 0); };
    function prep () {
        // meant for 4096x4096 canvas, slow as fuck
        var r = 0;
        var g = 0;
        var b = 0;
        for (var x = 0; x < canvas.width; x++) {
            for (var y = 0; y < canvas.height; y++) {
                set_pixel(x, y, r, g, b);
                b++;
                if (b > 255) {
                    b = 0;
                    g++;
                    if (g > 255) {
                        g = 0;
                        r++;
                    }
                }
            }
        }
        draw();
    };
    function preprandom () {
        // way prettier
        for (var x = 0; x < canvas.width; x++) for (var y = 0; y < canvas.height; y++) set_pixel(x, y, Math.floor(Math.random() * 255), Math.floor(Math.random() * 255), Math.floor(Math.random() * 255));
        draw();
    };
    function multi_pass_sort (lambda_x, lambda_y) {
        var sorted = true;
        for (var x = 1; x < canvas.width; x++) for (var y = 0; y < canvas.height; y++) if (lambda_x(get_pixel(x - 1, y), get_pixel(x, y))) { swap_pixels(x - 1, y, x, y); sorted = false; }
        for (var x = 0; x < canvas.width; x++) for (var y = 1; y < canvas.height; y++) if (lambda_y(get_pixel(x, y - 1), get_pixel(x, y))) { swap_pixels(x, y - 1, x, y); sorted = false; }
        draw();
        if (!sorted) setTimeout(function () { multi_pass_sort(lambda_x, lambda_y); }, 0);
        else console.log('done!');
    };
    //prep();
    preprandom();
    setTimeout(function () { multi_pass_sort(function lambda_x (a, b) { return a[0] > b[0] || a[1] > b[1]; }, function lambda_y (a, b) { return a[1] > b[1] || a[2] > b[2]; });
    }, 1000);
</script>

Try experimenting with the lambda_x and lambda_y functions and enjoy your exploration of the multidimensional!

AWK and friends.

Look mom! I've shaken the colors away!

The 'x' file:

BEGIN {
    N=5
    C=2^N
    print "P3\n"2^(3*N-int(3*N/2))" "2^int(3*N/2)"\n"C-1
    for(x=0;x<C;x++)
        for(y=0;y<C;y++)
            for(z=0;z<C;z++)
                print x^4+y^4+z^4"\t"x" "y" "z | "sort -n | cut -f2-" 
}

Run:

awk -f x > x.ppm

Output:

N=5:

N=5.png

N=6:

N=6.png

BASH with *nix commands

Some oneliners generating PPM format pictures

Ok... this sure will not be the most popular solution, but I think it is worth being mentioned because it shows (one way) how to build raster graphics with shell commands:

{ printf 'P3\n# x.ppm\n256 128\n31\n' ; printf '%s\n' {0..31}.{0..31}.{0..31} | tr . ' ' ; } >x.ppm

Output:

x

You can add other commands to that pipe to shuffle or rearrange the pixels... let's try 'sort':

{ printf 'P3\n# x.ppm\n256 128\n31\n' ; printf '%s\n' {0..31}.{0..31}.{0..31} | sort | tr . ' ' ; } >y.ppm

y

Ok... that was boring!

How about some random?

{ printf 'P3\n# x.ppm\n256 128\n31\n' ; printf '%s\n' ${RANDOM}.{0..31}.{0..31}.{0..31} | sort | awk -F. '{ print $2" "$3" "$4}' ; } >z.ppm

z

If you think this is fun, read about the PBM, PGM and PPM picture file formats.

They may look like a fossil but who says that this means "no fun!"?

  • It's no fossil if they have practical use, namely plain text format (and not BASE64 encoded or stuff) – Mark Jeronimus Mar 21 '14 at 11:44
  • "They may look like a fossil" is not "they are a fossil". Maybe I should have been more verbose to be understood faster... – yeti Mar 21 '14 at 15:15

Java, 24-bit (4096 by 4096)

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.JFrame;


public class ALLTHECOLORS{
    static class ImageComponent extends Component{
        private static final long serialVersionUID = 1L;
        private BufferedImage i;
        public ImageComponent(BufferedImage i){
            this.i=i;
        }
        public int width(){
            return 512;
        }
        public int height(){
            return 512;
        }
        public void paint(Graphics g){
            g.drawImage(i, 0, 0,width(),height(),null);
        }
    }
    static class ColorIterator implements Iterator<Color>{
        int r=0,g=0,b=0;
        public boolean hasNext() {
            return r<256;
        }
        public Color next(){
            Color c=new Color(255-r,255-g,255-b);
            b++;
            if(b>255){
                b=0;
                g++;
            }
            if(g>255){
                g=0;
                r++;
            }
            return c;
        }   
    }
    static double d(Color a,Color b){
        int dr=a.getRed()-b.getRed();
        int dg=a.getGreen()-b.getGreen();
        int db=a.getBlue()-b.getBlue();
        return Math.sqrt(dr*dr+dg*dg+db*db);
    }
    static int hue(Color c){
        return (int)(0.5+90*Color.RGBtoHSB(c.getRed(),c.getGreen(),c.getBlue(),null)[0]);
    }
    static int sat(Color c){
        return (int)(0.5+7*Color.RGBtoHSB(c.getRed(),c.getGreen(),c.getBlue(),null)[1]);
    }
    public static void main(String[]args) throws IOException{
        Random rand=new Random(System.currentTimeMillis()%1000);
        BufferedImage img=new BufferedImage(4096,4096,BufferedImage.TYPE_INT_RGB);
        Iterator<Color>it=new ColorIterator();
        List<Color>col=new ArrayList<>(256*256*256);
        while(it.hasNext())col.add(it.next());
        for(int i=0;i<col.size();i++){
            col.set(i,col.set(rand.nextInt(i+1),col.get(i)));
        }
        col.sort((a,b)->{
            int dels=sat(a)-sat(b);
            int delh=hue(a)-hue(b);
            return dels!=0?dels:delh;
        });
        it=col.iterator();
        for(int x=0;x<4096;x++){
            for(int y=0;y<4096;y++){
                img.setRGB(x, y,it.next().getRGB());
            }
        }
        ImageIO.write(img,"jpg",new File("the_colors.jpg"));
        JFrame frame=new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        ImageComponent c=new ImageComponent(img);
        frame.add(c);
        frame.setSize(new Dimension(c.width(),c.height()));
        frame.setVisible(true);
    }
}

It saves the full 4096 by 4096 version to the file "the_colors.jpg" and then draws a 1/8-size preview onto a JFrame. It typically takes 35-40 seconds to generate the result.

This is a fairly representative result (the 1/8-size preview is shown here, use the link to view at full size)

enter image description here

And here's a 10x close-up of a 25-by-25 portion of one of the blue-green sections: enter image description here

Python

Each run produces one of ~1.3 trillion possible outputs. Requires ImageMagick's display command.

#!/usr/bin/env python
from itertools import product
from math import log
from subprocess import Popen, PIPE
from random import shuffle

w = 256
h = 128
entropy = int(log(w * h, 2))
colors = 3
byte = 256
color_range = xrange(0, byte, byte / 2**(entropy/colors))
output = bytearray(w * h * colors)
bit_permutation = range(entropy)
shuffle(bit_permutation)

def shuffle_bits(n):
    shuffled = 0
    for b, bit in zip(bit_permutation, bin(n)[2:].zfill(entropy)):
        if bit == '1': shuffled += 1 << b
    return shuffled

for channels, pos in zip(product(color_range, repeat=colors),
                         map(shuffle_bits, xrange(w * h))):
    output[colors*pos:colors*(pos+1)] = ''.join(chr(k) for k in channels)

proc = Popen(
    ['display', '-size', '%sx%s' % (w, h), '-depth', '8', 'rgb:-'], stdin=PIPE)
proc.communicate(str(output))

Some outputs:

output example 1
output example 2
output example 3

Try changing w / h to 512 / 512 or 2048 / 1024 for more colors.

  • 5
    1.3 trillion frames at 30 FPS = 1373 years. Let's get that video started! – Jason C Mar 1 '14 at 2:51

Processing

Uses the same algorithm as the given example, but gives an animated output! Isn't it fun just to stare at your computer screen as the pixels slowly fill up one by one?

void setup(){
  size(256,128);
  background(0);
  frameRate(2400); //adjust as needed
}
int i=0;
void draw() {
  stroke(i<<3&255,i>>2&255,i>>7&255);
  point(i&255,i/256);
  i++;
}

See it run online here.

Here's a screenshot at the end of the animation:

enter image description here

  • You should change the point call to point(i&255,floor(i/256)); This will stop the second half being shifted down by one pixel with processing.js – curiousdannii Jun 9 '14 at 2:31

Javascript (jQuery), HTML and CSS

Result

Javascript will create a table containing one cell for each color. jQuery is used for styling table cells.

$(function() {
    $container = $('body > main > table#container > tbody');

    $td = $('<td>0</td>');

    var reds = [];
    var greens = [];
    var blues = [];

    for (var i = 0; i <= 256; i = i + 8)
    {
        reds.push(i);
        greens.push(i);
        blues.push(i);
    }

    var y_len = (reds.length * 4);
    var x_len = greens.length;
    var z_len = blues.length;

    var z = 0;
    var z_end = 0;

    for (var y = 0; y < y_len; y++)
    {
        $row = $('<tr></tr>');

        tmp_z = ((y % 4) * 8);
        tmp_z_end = (tmp_z + 8);

        for (var x = 0; x < x_len; x++)
        {
            for (var z = tmp_z; z < tmp_z_end; z++)
            {
                $pixel = $td
                    .clone()
                    .css({ 'background-color':
                        'rgb(' + reds[x] +','
                            + greens[Math.floor(y / 4)] + ','
                            + blues[z] + ')' })
                ;

                $row.append($pixel);
            }
        }

        $container.append($row, "\n");
    }
});

Result (warning: your browser will take some time to display the result)

Source

Java 8

The program attempts to color a Mandelbrot using every color. Naturally, this ensures that there are two parts of the program that take a long time: the color generation, and the Mandelbrot generation.

For each pixel of the image, I compute whether it is in or out of the Mandelbrot, before estimating the exterior difference for each exterior point. The interior distances are currently all set to 0. At this point, we sort according to the distance to the Mandelbrot Set, then grab the (sorted) color at the same position in the sort as the pixel.

To sort the color, I compute the hue and saturation according to these formulae. I sort by saturation, with hue coming in afterwards.

package mandelbrot;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.List;

public class Mandelbrot {
    public static final int WIDTH = 4096;
    public static final int HEIGHT = 4096;
    public static final int N = 1000; // Number of iterations
    public static final double R = 2; // Bailout radius
    public static final double MIN_X = -2.2;
    public static final double MAX_X = 1.4;
    public static final double MIN_Y = -1.2;
    public static final double MAX_Y = 1.2;

    private static double discreteToReal(int value, int maxValue, double min, double max) {
        return ((double) value) / maxValue * (max - min) + min;
    }

    private static boolean isDefinitelyInside(double x, double y) {
        double temp = x - 0.25;
        double q = temp * temp + y * y;
        return q * (q + (x - 0.25)) < 0.25 * y * y;
    }

    private static boolean isDefinitelyOutside(double x, double y) {
        if (!(-2 <= x && x <= 0.7)) return true;
        if (!(-1.2 <= y && y <= 1.2)) return true;
        if (x * x + y * y < 2 * 2) return true;
        return false;
    }

    private static boolean isInsideMandelbrot(double x0, double y0) {
        if (isDefinitelyInside(x0, y0)) return true;
        if (isDefinitelyOutside(x0, y0)) return false;

        double x = 0.0;
        double y = 0.0;
        int numIterations = 0;
        while (x * x + y * y < R * R && numIterations < N) {
            double xtemp = x * x - y * y + x0;
            y = 2 * x * y + y0;
            x = xtemp;
            numIterations++;
        }

        return x * x + y * y < R * R;
    }

    private static double distanceToMandelbrot(int px, int py) {
        double x0 = discreteToReal(px, WIDTH, MIN_X, MAX_X);
        double y0 = discreteToReal(py, WIDTH, MIN_Y, MAX_Y);

        if (isInsideMandelbrot(x0, y0)) return interiorDistanceEstimate(x0, y0);
        return exteriorDistanceEstimate(x0, y0);
    }

    private static double exteriorDistanceEstimate(double x0, double y0) {
        double pn_x = x0;
        double pn_y = y0;
        double derivative_pn = 1;

        for (int i = 0; i < N; i++) {
            double next_pn_x = pn_x * pn_x - pn_y * pn_y + x0;
            double next_pn_y = 2 * pn_x * pn_y + y0;
            double next_d_pn = 2 * pn_x * derivative_pn + 1;
            pn_x = next_pn_x;
            pn_y = next_pn_y;
            derivative_pn = next_d_pn;
        }

        double temp = Math.hypot(pn_x, pn_y);
        return 2 * temp * Math.log(temp) / Math.abs(derivative_pn);
    }

    private static double interiorDistanceEstimate(double x0, double y0) {
        return 0;
    }

    private static BufferedImage computeMandelbrot(List<Color> colors) {
        double[][] distances = new double[HEIGHT][WIDTH];

        double start = System.currentTimeMillis() * 1e-3;
        System.out.println("\tGenerating points...");

        List<Point> points = new ArrayList<>(WIDTH * HEIGHT);
        for (int x = 0; x < WIDTH; x++) {
            for (int y = 0; y < HEIGHT; y++) {
                points.add(new Point(x, y));
            }
        }
        Collections.shuffle(points, new Random(133));

        System.out.printf("\tElapsed time: %f%n", 1e-3 * System.currentTimeMillis() - start);
        start = 1e-3 * System.currentTimeMillis();
        System.out.println("\tCalculating Mandelbrot...");

        points.parallelStream()
                .forEach(xy -> {
                    int x = xy.x;
                    int y = xy.y;
                    distances[y][x] = distanceToMandelbrot(x, y);
                });

        System.out.printf("\tElapsed time: %f%n", 1e-3 * System.currentTimeMillis() - start);
        start = 1e-3 * System.currentTimeMillis();
        System.out.println("\tAttempting to match with colors...");

        Collections.sort(points, (a, b) -> {
            double bDistance = distances[b.y][b.x];
            double aDistance = distances[a.y][a.x];
            return Double.compare(aDistance, bDistance);
        });

        System.out.printf("\tElapsed time: %f%n", 1e-3 * System.currentTimeMillis() - start);
        start = 1e-3 * System.currentTimeMillis();
        System.out.println("\tConstructing image...");

        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);

        Iterator<Color> colorIterator = colors.iterator();
        for (Point xy : points) {
            image.setRGB(xy.x, xy.y, colorIterator.next().getRGB());
        }

        System.out.printf("\tElapsed time: %f%n", 1e-3 * System.currentTimeMillis() - start);

        return image;
    }

    public static void main(String[] args) throws IOException {
        double start = System.currentTimeMillis() * 1e-3;
        double veryBeginning = start;
        System.out.println("Generating colors...");
        List<Color> colors = new ArrayList<>(WIDTH * HEIGHT);

        for (int rgb = 0; rgb < WIDTH * HEIGHT; rgb++) {
            colors.add(new Color(rgb));
        }
        Collections.shuffle(colors, new Random(0));

        System.out.printf("Elapsed time: %f%n", 1e-3 * System.currentTimeMillis() - start);
        start = 1e-3 * System.currentTimeMillis();
        System.out.println("Sorting colors...");

        colors.sort((a, b) -> {
            BigDecimal r1 = BigDecimal.valueOf(a.getRed(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);
            BigDecimal g1 = BigDecimal.valueOf(a.getGreen(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);
            BigDecimal b1 = BigDecimal.valueOf(a.getBlue(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);

            BigDecimal r2 = BigDecimal.valueOf(b.getRed(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);
            BigDecimal g2 = BigDecimal.valueOf(b.getGreen(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);
            BigDecimal b2 = BigDecimal.valueOf(b.getBlue(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);

            BigDecimal cmax1 = r1.max(g1).max(b1);
            BigDecimal cmin1 = r1.min(g1).min(b1);

            BigDecimal cmax2 = r2.max(g2).max(b2);
            BigDecimal cmin2 = r2.min(g2).min(b2);

            BigDecimal delta1 = cmax1.subtract(cmin1);
            BigDecimal delta2 = cmax2.subtract(cmin2);

            BigDecimal h1 = delta1.compareTo(BigDecimal.ZERO) == 0 ?
                    BigDecimal.ZERO
                    : cmax1.compareTo(r1) == 0 ?
                    BigDecimal.valueOf(60).multiply(g1.subtract(b1).divide(delta1, RoundingMode.HALF_DOWN))
                    : cmax1.compareTo(g1) == 0 ?
                    BigDecimal.valueOf(60).multiply(b1.subtract(r1).divide(delta1, RoundingMode.HALF_DOWN).add(BigDecimal.valueOf(2)))
                    : BigDecimal.valueOf(60).multiply(r1.subtract(g1).divide(delta1, RoundingMode.HALF_DOWN)).add(BigDecimal.valueOf(4));
            if (h1.compareTo(BigDecimal.ZERO) < 0) {
                h1 = h1.add(BigDecimal.valueOf(360));
            }

            BigDecimal h2 = delta2.compareTo(BigDecimal.ZERO) == 0 ?
                    BigDecimal.ZERO
                    : cmax2.compareTo(r2) == 0 ?
                    BigDecimal.valueOf(60).multiply(g2.subtract(b2).divide(delta2, RoundingMode.HALF_DOWN))
                    : cmax2.compareTo(g2) == 0 ?
                    BigDecimal.valueOf(60).multiply(b2.subtract(r2).divide(delta2, RoundingMode.HALF_DOWN).add(BigDecimal.valueOf(2)))
                    : BigDecimal.valueOf(60).multiply(r2.subtract(g2).divide(delta2, RoundingMode.HALF_DOWN)).add(BigDecimal.valueOf(4));
            if (h2.compareTo(BigDecimal.ZERO) < 0) {
                h2 = h2.add(BigDecimal.valueOf(360));
            }

            return h1.compareTo(h2);
        });

        colors.sort((a, b) -> {
            BigDecimal r1 = BigDecimal.valueOf(a.getRed(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);
            BigDecimal g1 = BigDecimal.valueOf(a.getGreen(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);
            BigDecimal b1 = BigDecimal.valueOf(a.getBlue(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);

            BigDecimal r2 = BigDecimal.valueOf(b.getRed(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);
            BigDecimal g2 = BigDecimal.valueOf(b.getGreen(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);
            BigDecimal b2 = BigDecimal.valueOf(b.getBlue(), 100).divide(BigDecimal.valueOf(255), RoundingMode.HALF_DOWN);

            BigDecimal cmax1 = r1.max(g1).max(b1);
            BigDecimal cmin1 = r1.min(g1).min(b1);

            BigDecimal cmax2 = r2.max(g2).max(b2);
            BigDecimal cmin2 = r2.min(g2).min(b2);

            BigDecimal delta1 = cmax1.subtract(cmin1);
            BigDecimal delta2 = cmax2.subtract(cmin2);

            BigDecimal l1 = cmax1.add(cmin1).divide(BigDecimal.valueOf(2), RoundingMode.HALF_DOWN);
            BigDecimal l2 = cmax2.add(cmax2).divide(BigDecimal.valueOf(2), RoundingMode.HALF_DOWN);

            BigDecimal divisor1 = BigDecimal.ONE.subtract(l1.subtract(BigDecimal.ONE).abs());
            BigDecimal s1 = delta1.compareTo(BigDecimal.ZERO) == 0 || divisor1.compareTo(BigDecimal.ZERO) == 0 ?
                    BigDecimal.ZERO
                    : delta1.divide(divisor1, RoundingMode.HALF_DOWN);

            BigDecimal divisor2 = BigDecimal.ONE.subtract(l2.subtract(BigDecimal.ONE).abs());
            BigDecimal s2 = delta2.compareTo(BigDecimal.ZERO) == 0 || divisor2.compareTo(BigDecimal.ZERO) == 0 ?
                    BigDecimal.ZERO
                    : delta2.divide(divisor2, RoundingMode.HALF_DOWN);

            return s1.compareTo(s2);
        });

        System.out.printf("Elapsed time: %f%n", 1e-3 * System.currentTimeMillis() - start);
        start = 1e-3 * System.currentTimeMillis();
        System.out.println("Generating Mandelbrot...");
        BufferedImage mandelbrot = computeMandelbrot(colors);

        System.out.printf("Elapsed time: %f%n", 1e-3 * System.currentTimeMillis() - start);
        start = 1e-3 * System.currentTimeMillis();
        System.out.println("Writing to file...");
        ImageIO.write(mandelbrot, "png", new File("mandelbrot.png"));
        System.out.printf("Elapsed time: %f%n", 1e-3 * System.currentTimeMillis() - start);

        System.out.printf("%nTotal time: %f%n", 1e-3 * System.currentTimeMillis() - veryBeginning);
    }
}

As is, after running for 219 seconds, the code generates this image (screenshot as file is ~40MB):

enter image description here

I have no idea why the outside of the Mandelbrot is so random; it should have made use of my exterior distance estimate. Perhaps the inside is stealing too many of the colors....

If I remove the randomization on the points, I get this:

enter image description here

I get the feeling my exterior distance code is not working right...

  • exteriorDistanceEstimate() consistently returns NaN – Mark Jeronimus Jan 25 '16 at 20:30
  • @MarkJeronimus I figured that out. It returns NaN almost all the time (there are some times where it doesn't though) because the double values always get too large, resulting in Infinity, so dividing makes NaN. I've been working out some of the bugs and it's getting better – Justin Jan 25 '16 at 21:48

I was inspired by my answer from another popularity contest question which used iterative depth-first search to generate a maze. I used a variation of the algorithm used in a couple other answers that determines the best color to place at a certain pixel given the colors occupying the neighboring pixels. The algorithm starts at the center pixel and works its way visiting every pixel in the image in a random path.

The code is set up so that one can change the fields to give different results, such as adjusting the width and height of the image (and all relevant colors are used depending on the dimensions), random seed, and whether to shuffle or sort the colors before placing them from the list onto the image. Sorting is done using the HSV color model.

The resulting image will appear in a window once the image generation has finished. Scroll panes may be added for convenience in larger images. Assuming searchLimit = 8, on my machine it takes seconds to produce 256x128 and 512x512 images, around ten minutes for 2048x1024 images, and half a day or longer for 4096x4096 images.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.function.BinaryOperator;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class RGBImage {
    /**
     * Width and height of the image. Choose either of:
     * 128x256  256x128  512x512  1024x2048  2048x1024  4096x4096
     **/
    private final int width = 512, height = 512;

    /**
     * Number of colors from the front of the list to compare when searching
     * for the best color. Note: the higher this value, the longer it will take
     * to produce the image.
     **/
    private final int searchLimit = 8;

    /**
     * Seed for the color list shuffling and depth-first search algorithm.
     * Using the same seed will yield the same image provided no other
     * algorithm settings were altered. Add 'L' or 'l' after the value; e.g. 1L
     * Using 'null' will create a random image every time the program is run.
     **/
    private final Long seed = null;
    private final Random rand = new Random(seed == null ? System.nanoTime() : seed);

    /**
     * List of all colors.
     **/
    private List<Integer> colors;

    /**
     * Comparator to sort the colors. Use any of
     * null  byHue()  bySaturation()  byValue()  byRed()  byGreen()  byBlue()
     *
     * Using 'null' causes the colors to be sorted in ascending order by their
     * numerical value.
     * You can sort by one method first and then by another; e.g.
     * byHue().thenComparing(bySaturation());
     **/
    private final Comparator<Integer> comparator = null;

    /**
     * Flags for shuffling and sorting the values in the list.
     * If both flags are 'false', the colors in the list will be sorted in
     * ascending order by their numerical value.
     * If both flags are 'true', shuffling will occur first, then sorting. This
     * may give interesting results!
     **/
    private final boolean shuffle = false, sort = false;

    /**
     * The name to save the image as. The extension is "png" and should not be
     * included.
     **/
    private final String fileName = "output";

    public RGBImage() {
        init();

        int[] pixels = new int[width * height];
        Arrays.fill(pixels, -1);
        constructArray(pixels, new short[]{(short) (width/2), (short) (height/2)});

        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        img.setRGB(0, 0, width, height, pixels, 0, width);

        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame();
            JPanel panel = new JPanel() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(width, height);
                }

                @Override
                protected void paintComponent(Graphics g) {
                    super.paintComponent(g);
                    g.drawImage(img, 0, 0, this);
                }
            };
            frame.add(new JScrollPane(panel), BorderLayout.CENTER);

            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            if (width <= 512)
                frame.pack();
            else
                frame.setSize(750, 750);
            frame.setVisible(true);
        });

        try {
            ImageIO.write(img, "png", new File(fileName + ".png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    private void init() {
        colors = new ArrayList<>(width * height);
        int bitsPerComp = (int) (Math.log(width * height) / Math.log(2)) / 3;
        int pow2 = 1 << bitsPerComp, fact256 = 256 / pow2;

        float adj = 255f / (256 - fact256);
        for (int k = 0; k < width * height; k++) {
            int r = (int) (((k >> (bitsPerComp * 2)) % pow2) * fact256 * adj) << 16,
                g = (int) (((k >> bitsPerComp) % pow2) * fact256 * adj) << 8,
                b = (int) ((k % pow2) * fact256 * adj);
            colors.add(r | g | b);
        }
        if (shuffle)
            Collections.shuffle(colors);
        if (sort)
            Collections.sort(colors, comparator);
    }

    private void constructArray(int[] pixels, short[] coord) {
        Deque<short[]> path = new LinkedList<>();
        path.add(coord);
        boolean up, right, down, left;
        while (true) {
            coord = path.peekFirst();
            int col = bestColor(pixels, coord);
            pixels[coord[1] * width + coord[0]] = col;
            colors.remove(Integer.valueOf(col));

            if (isSurrounded(pixels, coord)) {
                do {
                    coord = path.removeFirst();
                } while (isSurrounded(pixels, coord) && !path.isEmpty());
            }

            if (path.isEmpty())
                break;

            up = coord[1] != 0 && pixels[(coord[1] - 1) * width + coord[0]] == -1;
            right = coord[0] != width - 1 && pixels[coord[1] * width + coord[0] + 1] == -1;
            down = coord[1] != height - 1 && pixels[(coord[1] + 1) * width + coord[0]] == -1;
            left = coord[0] != 0 && pixels[coord[1] * width + coord[0] - 1] == -1;

            byte size = 0;
            if (up) size++;
            if (right) size++;
            if (down) size++;
            if (left) size++;

            byte[] possible = new byte[size];
            if (up) possible[--size] = 0;
            if (right) possible[--size] = 1;
            if (down) possible[--size] = 2;
            if (left) possible[--size] = 3;

            switch (possible[rand.nextInt(possible.length)]) {
                case 0: path.addFirst(new short[] {coord[0], (short) (coord[1] - 1)}); break;
                case 1: path.addFirst(new short[] {(short) (coord[0] + 1), coord[1]}); break;
                case 2: path.addFirst(new short[] {coord[0], (short) (coord[1] + 1)}); break;
                case 3: path.addFirst(new short[] {(short) (coord[0] - 1), coord[1]}); break;
            }
        }
    }

    private boolean isSurrounded(int[] pixels, short[] c) {
        return (c[1] == 0 ? true : pixels[(c[1] - 1) * width + c[0]] != -1) &&
               (c[0] == width - 1 ? true : pixels[c[1] * width + c[0] + 1] != -1) &&
               (c[1] == height - 1 ? true : pixels[(c[1] + 1) * width + c[0]] != -1) &&
               (c[0] == 0 ? true : pixels[c[1] * width + c[0] - 1] != -1);
    }

    private int bestColor(int[] pixels, short[] coord) {
        return colors
                .subList(0, Math.min(colors.size(), searchLimit))
                .parallelStream()
                .reduce(BinaryOperator.minBy(
                    Comparator.comparingDouble(col ->
                        Arrays.stream(getNeighbors(coord))
                            .filter(s -> s != null)
                            .mapToInt(s -> pixels[s[1] * width + s[0]])
                            .filter(i -> i != -1)
                            .mapToDouble(i -> HSVdiff(col, i))
                            .sum()
                    )
                ))
                .orElseThrow(() -> new RuntimeException("No best color found"));
    }

    private short[][] getNeighbors(short[] arr) {
        short[][] res = new short[8][2];
        byte index = 0;
        for (; index < 8; index++)
            res[index] = null;
        index = 0;
        for (short cx = (short) (arr[0] - 1); cx <= arr[0] + 1; cx++) {
            if (cx < 0 || cx == width) continue;
            for (short cy = (short) (arr[1] - 1); cy <= arr[1] + 1; cy++) {
                if (cy < 0 || cy == height) continue;
                if (cx == arr[0] && cy == arr[1]) continue;
                res[index++] = new short[] {cx, cy};
            }
        }
        return res;
    }

    private double HSVdiff(int c1, int c2) {
        float[] hsv1 = Color.RGBtoHSB(c1 >> 16, (c1 >> 8) & 0xff, c1 * 0xff, null),
                hsv2 = Color.RGBtoHSB(c2 >> 16, (c2 >> 8) & 0xff, c2 * 0xff, null);
        return Math.pow(hsv2[0] - hsv1[0], 2) + Math.pow(hsv2[1] - hsv1[1], 2) + Math.pow(hsv2[2] - hsv1[2], 2);
    }

    private Comparator<Integer> byHue() {
        return Comparator.comparingDouble(col -> Color.RGBtoHSB(col >> 16, (col >> 8) & 0xff, col & 0xff, null)[0]);
    }

    private Comparator<Integer> bySaturation() {
        return Comparator.comparingDouble(col -> Color.RGBtoHSB(col >> 16, (col >> 8) & 0xff, col & 0xff, null)[1]);
    }

    private Comparator<Integer> byValue() {
        return Comparator.comparingDouble(col -> Color.RGBtoHSB(col >> 16, (col >> 8) & 0xff, col & 0xff, null)[2]);
    }

    private Comparator<Integer> byRed() {
        return Comparator.comparingInt(col -> col >> 16);
    }

    private Comparator<Integer> byGreen() {
        return Comparator.comparingInt(col -> (col >> 8) & 0xff);
    }

    private Comparator<Integer> byBlue() {
        return Comparator.comparingInt(col -> col & 0xff);
    }

    public static void main(String[] args) {
        new RGBImage();
    }
}

Here's a random 512x512 image, unsorted (colors are stored in the list in ascending numerical order), searchLimit = 8:

512x512_search8

The next three are 512x512, use seed = 24680L, and shuffled the colors in the list without sorting them afterward. The searchLimit was the only thing that changed between them, producing interesting results.

searchLimit = 8:

512x512_search8_seed24680_shuffle

searchLimit = 128:

512x512_search128_seed24680_shuffle

searchLimit = 2048:

512x512_search2048_seed24680_shuffle

Some 256x128 images, seed = 24680, searchLimit = 64, the first sorted by hue, the second sorted by saturation, the third sorted by value, and the fourth shuffled and then sorted by value:

256x128_search64_seed24680_sortHue 256x128_search64_seed24680_sortSat 256x128_search64_seed24680_sortVal 256x128_search64_seed24680_shuffle_sortVal

Linked are 2048x1024 images, with seed = 24680 and the colors sorted by hue. Some interesting differences arise when modifying the searchLimit again. The ones used here are searchLimit = 8 and searchLimit = 512.

And last, but certainly not least, linked is a random 4096x4096 image with searchLimit = 8 and sorted by hue.

Java

This is similar to my other answer, but

By inserting this code:

for (int iy = 0; iy < 256; iy++) {
    for (int ix = 0; ix < 256; ix++) {
        for (int y = 0; y < 16; y++) {
            for (int x = 0; x < 16; x++) {
                int rgb = img_cln.getRGB((x << 8) + ix, (y << 8) + iy);
                img.setRGB(x + (ix << 4), y + (iy << 4), rgb);
            }
        }
    }
}

Like so:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

/**
 *
 * @author Quincunx
 */
public class AllColorImage {

    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);
        BufferedImage img_cln = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);

        for (int r = 0; r < 256; r++) {
            for (int g = 0; g < 256; g++) {
                for (int b = 0; b < 256; b++) {
                    img_cln.setRGB(((r & 15) << 8) | g, ((r >>> 4) << 8) | b, (((r << 8) | g) << 8) | b);
                }
            }
        }

        for (int iy = 0; iy < 256; iy++) {
            for (int ix = 0; ix < 256; ix++) {
                for (int y = 0; y < 16; y++) {
                    for (int x = 0; x < 16; x++) {
                        int rgb = img_cln.getRGB((x << 8) + ix, (y << 8) + iy);
                        img.setRGB(x + (ix << 4), y + (iy << 4), rgb);
                    }
                }
            }
        }

        try {
            ImageIO.write(img, "png", new File("Filepath"));
        } catch (IOException ex) {
            Logger.getLogger(AllColorImage.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

I can get this output:

enter image description here

I'm still trying to figure out how to remove those lines.

  • 10
    Have you trying turning it off and on again? – Pierre Arlaud Feb 27 '14 at 12:36
  • 4
    those are caused by some LSB bits; almost all of our loop-based ones have those little annoyances and they are a royal pain in the ass to remove – masterX244 Feb 27 '14 at 13:35
  • 5
    @ArlaudPierre Blowing on it might work, too. – Jason C Feb 28 '14 at 3:48

I know I'm a late to this discussion but I thought I would post my attempt to this thread just in case it is useful/interesting to anyone.

GLSL

vec3 xy2rgb3( in vec2 pos ) {
    vec2 rc = pos * 8.0;
    vec2 mp = fract( rc );
    rc = (rc - mp) * 0.125;
    return vec3( (rc.y * 0.125) + rc.x, mp );
}

The live editable version can be found here xy2rgb3/rgb3toxy2.

enter image description here

Mathematica

Flatten[Table[{r, g, b}, {r, 0, 1, 1/31}, {g, 0, 1, 1/31}, {b, 0, 1, 
 1/31}], 2]~Partition~256 // Image

enter image description here

RandomSample@
   Flatten[Table[{r, g, b}, {r, 0, 1, 1/31}, {g, 0, 1, 1/31}, {b, 0, 1, 
 1/31}], 2]~Partition~256 // Image

enter image description here

  • > or grid that can be screenshot and saved at 256×128 Please do this or I'll have to disqualify it – Mark Jeronimus Feb 26 '14 at 9:13
  • Still not exactly right, and also I count way less colors than supposed, including stretches of equal colors delimited by what looks like color-reducing dithering. – Mark Jeronimus Feb 26 '14 at 9:31
  • Better: n=31;ArrayPlot[ Partition[ Flatten@Table[ RGBColor[r/n, g/n, b/n], {r, 0, n}, {g, 0, n}, {b, 0, n}], 256], ImageSize -> {256, 128}] – DavidC Feb 26 '14 at 17:57
  • Zom-B. You may express your disagreement or dislike for a submission. But you cannot, by yourself, disqualify it. – DavidC Feb 26 '14 at 19:40
  • Shorter version: Image[Range[0,1,1/31]~Tuples~3~Partition~256] – Simon Woods Mar 1 '14 at 10:59

Processing with Xorshift

Xorshift is a type of PRNG which is very fast and somewhat reliable. A 16bit Xorshift generator will cycle through the numbers 1 to 65535, so for this task we skip any with the high bit set. What it won't do is ever produce the number 0, so we start painting at the second pixel. Each seed will produce the same result, and if you like you can try other seeds. Try it online.

enter image description here

void setup() {
    size(256,128);
    background(0);
}

int seed=1;
int xorshift() {
    seed ^= (seed << 13);
    seed ^= (seed >> 9);
    seed ^= (seed << 7);
}

void draw() {
    int i=1;
    while (i < 32768) {
        xorshift();
        while (seed > 32767) {
            xorshift();
        }
        stroke(seed<<3&255,seed>>2&255,seed>>7&255);
        point(i&255,floor(i/256));
        i++;
    }
    exit();
}

(Thank you to ace for the Processing boilerplate code.)

  • 1
    Just use all the values above 32767, discard the top bit, and you don't have to skip 0. – Mark Jeronimus Oct 14 '14 at 11:02

Mathematica

Non-competing because the builtt-in HilbertCurve was introduced in Mathematica 11.1 in 2017.

Inspired by Joe K's answer. Generates 9 images in one program. Arranges the colors in three different orderings: the lexicographical order, the Z-order curve, the Hilbert curve; then places them in the image in (the 2-dimensional version of) these three orderings.

f[m_, n_] := {Tuples[Range[2^m] - 1, n],
   FromDigits[Partition[#, n], 2] & /@ Tuples[{0, 1}, n*m],
   First@HilbertCurve[m, n]};

Table[Image@Partition[a[[Ordering@b]]/2^6, 2^9], {a, f[6, 3]}, {b, f[9, 2]}]

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

Excel VBA, 165 bytes

A declared subroutine that takes no input and outputs to a 256 x 128 cell image to the range A1:IV128. For this algorithm, red values change as a function of the column number, blue values changes as a function of row number and green values change as a function of both the column and row number, with low values falling at the top left and high values falling at the bottom right.[!

Option Compare Text
Option Explicit
Option Base 0

Public Sub c()

    Dim row As Integer, _
        col As Integer

    Let Cells.ColumnWidth = 2.15
    Let Cells.RowHeight   = 16
    For col = rgbBlack To rgbRed
        For row = rgbBlack To 127
            Let Cells(row + 1, col + 1).Interior.Color = RGB( _
                                                        Red     := 8 * (col Mod 32), _
                                                        Green   := 8 * (Int(col / 32) + 8 * Int(row / 32)), _
                                                        Blue    := 8 * (row Mod 32))
    Next row, col
End Sub

This may be golfed down to a VBE immediate window function worth 165 bytes.

Cells.ColumnWidth=2.15:Cells.RowHeight=16:For c=0To 255:For r=0To 127:Cells(r+1,c+1).Interior.Color=RGB(8*(c Mod 32),8*(Int(c/32)+8*Int(r/32)),8*(r Mod 32)):Next r,c

Output

All Colors from Excel VBA

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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