visit
While thinking of posts to write about, the title "Fun with Flags" came to mind and I wondered how I might connect that to programming. There are enum flags in C# via the Flags
attribute so maybe that was something I could write about. That said, I wanted to do something more creative than some humdrum post about using enums even if the end result isn't really practical.
Instead, I decided to make real flags in C# with enums - turning a number like 52357729848
into a flag:
There are technical limitations too as I can't store a lot of data in an enum and will need to make compromises. An enum can be backed by a few different types but I chose long
so I could get a full 64-bits of data to play with.
My initial thought with this was to pick the easiest form of flag - simple flags with stripes. If I split a typical flag into 9 segments, maybe I can store 9 colours and that would allow drawing of horizontal and vertical stripes. It seemed like the most straightforward approach at the time (I realised later it might have been better if I stored "shape" data instead for more flag variety but oh well).
[PPPPPPPPPP]
[RRGGBB][RRGGBB][RRGGBB]
[RRGGBB][RRGGBB][RRGGBB]
[RRGGBB][RRGGBB][RRGGBB]
P = Padding
R = Red Intensity
G = Green Intensity
B = Blue Intensity
public enum Intensity : byte
{
None = 0,
OneThird = 1,
TwoThirds = 2,
Max = 3
}
00000000 // Intensity.None
00000001 // Intensity.OneThird
00000010 // Intensity.TwoThirds
00000011 // Intensity.Max
public enum Colour : long
{
Black = 0,
Red = Intensity.Max << 4,
Green = Intensity.Max << 2,
Blue = Intensity.Max,
White = Red | Green | Blue
}
While we are using a long
here (helping us with our later bit shifting operations), the values we are setting fit within 6-bits. Viewing the colours as bytes in binary, the shifting and OR-ing of data would look a little like this:
00110000 // Red = Intensity.Max << 4
00001100 // Green = Intensity.Max << 2
00000011 // Blue = Intensity.Max
00111111 // White = Red | Green | Blue
00110000 // Red = Intensity.Max << 4
00001000 // Green = Intensity.TwoThirds << 2
00000000 // Blue = Intensity.None
========
00111000 // Yellow = (Intensity.Max << 4) | (Intensity.TwoThirds << 2)
public enum Colour : long
{
Black = 0,
Red = Intensity.Max << 4,
Green = Intensity.Max << 2,
Blue = Intensity.Max,
White = Red | Green | Blue,
Orange = (Intensity.Max << 4) |
(Intensity.OneThird << 2),
Yellow = (Intensity.Max << 4) |
(Intensity.TwoThirds << 2),
MediumGreen = Intensity.TwoThirds << 2,
LightBlue = (Intensity.TwoThirds << 2) |
Intensity.Max,
DarkBlue = Intensity.OneThird
}
public enum CountryFlags : long
{
Germany = Colour.Black << 48 | Colour.Black << 42 | Colour.Black << 36 |
Colour.Red << 30 | Colour.Red << 24 | Colour.Red << 18 |
Colour.Yellow << 12 | Colour.Yellow << 6 | Colour.Yellow
}
While Colour.Black
does encode as 0
so the first 3 values aren't actually needed, it made it easier to still think of it as 9 distinct segments that all needed colours set.
00000000 // Black, shifted by 48-bits
00000000
00000000
00110000 // Red, shifted by 30-bits
00110000
00110000
00111000 // Yellow, shifted by 12-bits
00111000
00111000
================================================================
0000000000000000000000000000000
As a decimal, that would be 52357729848
. This is only half the job though, we have our flag data as a number but we also need to decode it to an image.
So how do we take 52357729848
and turn it into an image? We use more bit shifting and now AND-ing of our data to get each individual colour. Also, we will be reading the data in reverse.
var blueComponent = (byte)(flagData & 3) * 85;
The value flagData
here is a long
of our generated number.
0000000000000000000000000000000
// We only want this part ^^
By doing flagData & 3
, we get just the last 2-bits from the full value. To get the next components, we do the same but now on a bit shifted value so the last 2-bits are of the colour we want.
var greenComponent = (byte)((flagData >> 2) & 3) * 85;
var redComponent = (byte)((flagData >> 4) & 3) * 85;
using var image = new Image<Rgb24>(3, 3);
for (var y = 2; y >= 0; --y)
{
for (var x = 2; x >= 0; --x)
{
var pixel = image[x, y];
var blueComponent = (byte)((flagData >> 0) & 3) * 85;
pixel.B = (byte)blueComponent;
var greenComponent = (byte)((flagData >> 2) & 3) * 85;
pixel.G = (byte)greenComponent;
var redComponent = (byte)((flagData >> 4) & 3) * 85;
pixel.R = (byte)redComponent;
flagData >>= 6;
image[x, y] = pixel;
}
}
In our inner-most loop, we also shift our bits in flagData
over 6-bits so we are in the next segment for the next iteration. This code though would only leave us with a 3x3 flag which doesn't look right so with a little more code, we can make it be bigger and more flag-like.
image.Mutate(x => x.Resize(400, 240, new NearestNeighborResampler()));
The NearestNeighborResampler
here is important - it allows us to scale up our specific "blocky" image here without distorting or blurring it.
//funwithflags.turnerj.com/api/flag/generate.png?v=ENCODED_VALUE
Germany = Colour.Black << 48 | Colour.Black << 42 | Colour.Black << 36 |
Colour.Red << 30 | Colour.Red << 24 | Colour.Red << 18 |
Colour.Yellow << 12 | Colour.Yellow << 6 | Colour.Yellow,
Italy = Colour.MediumGreen << 48 | Colour.White << 42 | Colour.Red << 36 |
Colour.MediumGreen << 30 | Colour.White << 24 | Colour.Red << 18 |
Colour.MediumGreen << 12 | Colour.White << 6 | Colour.Red,
France = Colour.DarkBlue << 48 | Colour.White << 42 | Colour.Red << 36 |
Colour.DarkBlue << 30 | Colour.White << 24 | Colour.Red << 18 |
Colour.DarkBlue << 12 | Colour.White << 6 | Colour.Red,
Ireland = Colour.MediumGreen << 48 | Colour.White << 42 | Colour.Orange << 36 |
Colour.MediumGreen << 30 | Colour.White << 24 | Colour.Orange << 18 |
Colour.MediumGreen << 12 | Colour.White << 6 | Colour.Orange,
Luxembourg = Colour.Red << 48 | Colour.Red << 42 | Colour.Red << 36 |
Colour.White << 30 | Colour.White << 24 | Colour.White << 18 |
Colour.LightBlue << 12 | Colour.LightBlue << 6 | Colour.LightBlue,