Search code examples
c#.netgraphicsgdi+gdi

Random color in C#


Is there any way to simplify this line of code? Are two calls to Color.FromArgb() really necessary?

Color c = Color.FromArgb(255, Color.FromArgb(Convert.ToInt32(rand.Next(0x1000000))));

Without the duplicated Color.FromArgb() call I get only Alpha=0 colors.

References:

How do I generate random dark colors in C#?


Solution

  • Just tried this in LinqPad and it seemed to do the trick:

    var random = new Random();
    System.Drawing.Color c;
    unchecked
    {
        var n = (int)0xFF000000 + (random.Next(0xFFFFFF) & 0x7F7F7F);
        Console.WriteLine($"ARGB: {n}");
        c = System.Drawing.Color.FromArgb(n);
    }
    Console.WriteLine($"A: {c.A}");
    Console.WriteLine($"R: {c.R}");
    Console.WriteLine($"G: {c.G}");
    Console.WriteLine($"B: {c.B}");
    

    More concisely, it would be:

    var random = new Random();
    Color c;
    unchecked
    {
        c = Color.FromArgb((int)0xFF000000 + (random.Next(0xFFFFFF) & 0x7F7F7F));
    }
    

    Or if you want to get really funky with bit manipulation (this is not more efficient, just saves you typing some 0s):

    c = Color.FromArgb((int)(0xFF << 24 ^ (random.Next(0xFFFFFF) & 0x7F7F7F)));
    

    Original poster pointed out that an extra pair of brackets eliminates the need for unchecked:

    c = Color.FromArgb((int)(0xFF000000 + (random.Next(0xFFFFFF) & 0x7F7F7F)));
    

    Bit of an explanation. ARGB is using a signed 32 bit int to represent four bytes, A, R, G, and B. We want the colour to be solid, so A needs to be 255 hence: 0xFF000000 Then random.Next(0xFFFFFF) generates a pseudo-random 24 bit number taking care of the R, G and B bytes. As the question only wanted dark colours we mask off the most significant bit of each byte. For a simple example, say the RNG spat out the max value (equivalent to white):

    0xFFFFFF = 111111111111111111111111

    We then do a bitwise AND to chop off the most significant bits:

    0x7F7F7F = 011111110111111101111111

    111111111111111111111111 & 011111110111111101111111 = 011111110111111101111111