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 in C# via the 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. from a certain TV show enum flags Flags Instead, I decided to make flags in C# with enums - turning a number like into a flag: real 52357729848 I gave myself certain requirements: I needed to be able to generate more than one flag I wanted to encode everything about the flag in a single value via enums 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 so I could get a full 64-bits of data to play with. long Encoding a Value 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 The problem is, storing 9 segments in 64 bits is pretty hard and would leave me with about 7.11-bits per segment making colour data very limited. I wanted 3 colour channels so that only gives me really 2-bits per colour which is not a lot of variety. Having then 6-bits per segment left me with 10-bits that I don't really have much use for. Initially, I tried using those bits to help extend the range of colours, acting as a multiplier for a specific channel. In the end though, it wasn't overly useful for this so I cut it. This is the data structure I ended with: [PPPPPPPPPP] [RRGGBB][RRGGBB][RRGGBB] [RRGGBB][RRGGBB][RRGGBB] [RRGGBB][RRGGBB][RRGGBB] P = Padding R = Red Intensity G = Green Intensity B = Blue Intensity My primary data only takes 54-bits so my data structure has 10-bits of padding at the front. Having the padding at the front allows the generated number to be smaller. I will be using for converting this value into an actual image. Because I have 9 segments, it seemed like the best idea to treat the image as a 3x3 pixel square and get ImageSharp to resize it for me. The pixel format for the data though was RGB24 so I needed to work out how to scale up my colours from 2-bits to 8-bits per channel. ImageSharp With 8-bits, the max value I can have is 255 for a single channel. Full-colour intensity for any channel is 3 so I decided to simply divide the max value by the full-colour intensity leaving me the magic number of 85 to scale my values by. That is the nuts-and-bolts of the format, now it was just to make that work in code. A Bit Shifty Knowing I can store the data is one thing, actually making it work was another. I don't often use but for this, it was going to use them quite heavily. Bitwise and shift operators Firstly, we need an enum of colour intensity values: public enum Intensity : byte { None = 0, OneThird = 1, TwoThirds = 2, Max = 3 } The specific values here are important because of what they represent in binary. 00000000 // Intensity.None 00000001 // Intensity.OneThird 00000010 // Intensity.TwoThirds 00000011 // Intensity.Max Because these values represent a single channel's intensity, we need to combine 3 of them together to form our full colour. We combine them by using bit shifting and bitwise OR operations to create our 6-bit colour value. 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 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: long 00110000 // Red = Intensity.Max << 4 00001100 // Green = Intensity.Max << 2 00000011 // Blue = Intensity.Max 00111111 // White = Red | Green | Blue Using different intensity values for the different colour channels, we can create new colours too. 00110000 // Red = Intensity.Max << 4 00001000 // Green = Intensity.TwoThirds << 2 00000000 // Blue = Intensity.None ======== 00111000 // Yellow = (Intensity.Max << 4) | (Intensity.TwoThirds << 2) To create a few different types of flags, we will need a few more colours... 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 } Identifying the right combinations of values for colours was relatively straightforward - I used an RGB colour picker in and selected thirds of the different colour channels. Like if I had two-thirds red and one-third green, I'd approximately have orange. Paint.NET So now we've got our colours, we need to encode the final value of a flag. In a similar approach to combining the colour channels, we need to combine the colours of the 9 segments by shifting and OR-ing. 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 does encode as 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. Colour.Black 0 In binary, the operation to encode our German flag would look like: 00000000 // Black, shifted by 48-bits 00000000 00000000 00110000 // Red, shifted by 30-bits 00110000 00110000 00111000 // Yellow, shifted by 12-bits 00111000 00111000 ================================================================ 0000000000000000000000000000110000110000110000111000111000111000 As a decimal, that would be . 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. 52357729848 Generating an Image So how do we take 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. 52357729848 var blueComponent = (byte)(flagData & 3) * 85; The value here is a of our generated number. flagData long To get the blue component, we don't need to shift but we do need to perform a logical AND of the data. We only want the last two bits of the number - if we just convert the number to a byte, we will get the last 8-bits. 0000000000000000000000000000110000110000110000111000111000111000 // We only want this part ^^ By doing , 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. flagData & 3 var greenComponent = (byte)((flagData >> 2) & 3) * 85; var redComponent = (byte)((flagData >> 4) & 3) * 85; Now we have the 3 colour channels of the bottom right segment of our flag. As a reminder, the 85x multiplier is to adjust the colour to fit within a full 8-bits for the RGB24 pixel format. Really now, it is just a matter of wrapping the code within some loops to set it to an image. 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 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. flagData image.Mutate(x => x.Resize(400, 240, new NearestNeighborResampler())); The here is important - it allows us to scale up our specific "blocky" image here without distorting or blurring it. NearestNeighborResampler And that's basically it - we can take a bunch of enums and encode a value then take the value and decode it to an image. I've set up an Azure Function running this code to show it working and a few flags I've generated: https://funwithflags.turnerj.com/api/flag/generate.png?v=ENCODED_VALUE Germany Value: 52357729848 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 Value: 2532184938287088 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 Value: 561852585091056 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 Value: 2532459817242612 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 Value: 13725272368788171 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, Final Thoughts What started out as a bit of a weird challenge I set myself turned into a fun and interesting learning experience. I rarely mess around with bit shifting and bitwise operations. While I still probably won't need to very often, I like that I know a lot more about them now. If I were to approach this again, I'd probably look at encoding shapes instead of pixels of colours. That way I could encode a wider variety of flags like the flags of Sweden, Japan and perhaps even South Korea. If you liked this... If you liked the kinda strange and interesting nature of this, you might like my deep dive into Levenshtein Distance and the various optimizations. Levenshtein Distance (Part 1: What is it?) Levenshtein Distance (Part 2: Gotta Go Fast) Levenshtein Distance (Part 3: Optimize Everything!) Levenshtein Distance with SIMD