Search code examples
c#imagecolorsbmpprocedural

Magic numbers in color-to-image space transformation


Please disregard below; I forgot how integer overflow works >.<

After seeing the incredible answers on this Code Golf question, I thought I might mess around with generating my own images in C#. I stumbled around for a while trying to make an XOR plot and found that directly writing to components (e.g. red = a ^ b) didn't work, but writing trig functions around logarithms around a core a ^ b did; is there any reason for that?

Core color generator (plots an XOR graph):

ColorVec currColor = new ColorVec((float)Math.Sin(Math.Log(j ^ i)),
                                  (float)Math.Cos(Math.Log(j ^ i)),
                                  (float)Math.Tan(Math.Log(i ^ j)));

Constructor for ColorVec:

public ColorVec(float xR, float yG, float zB)
{
    red = xR;
    green = yG;
    blue = zB;
}

Functions to convert between floating-point colors and the eight-bit colors expected by Bitmap:

public byte GetIntRed()
{
   return (byte)(red * 255);
}

public byte GetIntGreen()
{
   return (byte)(green * 255);
}

public byte GetIntBlue()
{
   return (byte)(blue * 255);
}

Program code:

class Program
{
    static void Main(string[] args)
    {
        short width = 2048;
        Random rand = new Random();
        Bitmap imageWriting = new Bitmap(width, width);

        for (short i = 0; i < width; i += 1)
        {
            Console.WriteLine(String.Concat("Working... (writing batch ", i, " of ", width, ")"));

            for (short j = 0; j < width; j += 1)
            {
                ColorVec currColor = new ColorVec((float)Math.Sin(Math.Log(j ^ i)),
                                                  (float)Math.Cos(Math.Log(j ^ i)),
                                                  (float)Math.Tan(Math.Log(i ^ j)));

                imageWriting.SetPixel(i, j, Color.FromArgb(1, currColor.GetIntRed(),
                                                              currColor.GetIntGreen(),
                                                              currColor.GetIntBlue()));
            }
        }

        imageWriting.Save("test.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
    }
}

Solution

  • I think that question is not very clear, but still will try to provide some thoughts.

    So you are trying in some sense to draw a 3D plot: two variables are i and j coodinate and third variable is color. Your function i^j (or any other such function) returns an integer, and now you need to map that integer to some color. This can be done in many ways, most straight-forward is just:

    var color = Color.FromArgb(i ^ j); // will produce more clear plot than your way
    

    This will treat one byte of the result as aplha, and 3 others as r\g\b parts. You are using another way, but it does not have any special meaning. Sin, Cos, Tan functons just have range (-1;1), so when you multiply the result by 255 and convert to byte (conversion of negative float to byte also works) - you get a valid color part. Log function is not necessary, but if you apply it - resulting colors will be just different.