C# Software Bitmap Utility
Author: HS_Dave
- Posted on: 17/04/2015
Post Type: Blog Entry
So I've been working on some procedural content for Dodeka (more details on that in next dev update!) and I needed a way to visualise it as I worked on it so I could see exactly what I was doing. Originally I output ASCII to a text file but that really was not ideal.

The obvious choice is to create an image then. The problem is that I needed to quickly create a LARGE (giant even) image which is a problem when dealing with XNA Texture2D objects because they are all stored on the graphics card which severely limits the maximum size. I did not have access to System.Drawing in this project and nor did I wish to add it.

Googling around a bit I found I was not alone in this problem however there were little in satisfactory solutions. So what I've done is knock up a very quick (*see foot note) software bitmap handler for C#. It relies on very little and does NOT use unsafe to do it's stuff.

It's not fast and it's not full featured - but it does allow you to very easily create bitmap images, edit them programmatically and then save them to disk in a proper format for your OS to open and display. As I found I was not alone in needing this I've decided to share it, so here it is:

HS_Bitmap.cs

Feel free to use/modify/whatever. It does not really have a real-time application as it's not fast - but as a utility it may be very useful. I have thrown in some basic inline documentation for your intellisense etc - if you'd like more details on the bitmap format then check wikipedia, it's where I got the info from!

As a bonus, here's a quick example of how you would copy an XNA Texture2D into the bitmap object if you wanted to do tile map representation:

First load your image data and create your objects:

    HS_Bitmap WorldBmp = new HS_Bitmap(WorldWidth * TileSize, WorldHeight * TileSize);
    HS_Bitmap WaterBmp = new HS_Bitmap(TileSize, TileSize);
    HS_Bitmap PlainsBmp = new HS_Bitmap(TileSize, TileSize);
    HS_Bitmap MountainBmp = new HS_Bitmap(TileSize, TileSize);

    Texture2D WaterImg = SystemVars.g_MainContentManager.Load<Texture2D>("DATA_2D\\Dodeka\\Water");
    Texture2D PlainsImg = SystemVars.g_MainContentManager.Load<Texture2D>("DATA_2D\\Dodeka\\Plains");
    Texture2D MountainImg = SystemVars.g_MainContentManager.Load<Texture2D>("DATA_2D\\Dodeka\\Mountain");
            
Create some arrays to hold colour data and copy the XNA Texture2D data into them:

    Color[] WaterPixels = new Color[TileSize * TileSize];
    Color[] PlainsPixels = new Color[TileSize * TileSize];
    Color[] MountainPixels = new Color[TileSize * TileSize];

    WaterImg.GetData<Color>(WaterPixels);
    PlainsImg.GetData<Color>(PlainsPixels);
    MountainImg.GetData<Color>(MountainPixels);

Set the HS_Bitmap pixel data to match the Texture2D Color data:

for (int x = 0; x < TileSize; x++ )
{
    for (int y = 0; y < TileSize; y++)
    {
        WaterBmp.SetPixel(x, y, WaterPixels[y * TileSize + x].R, WaterPixels[y * TileSize + x].G, WaterPixels[y * TileSize + x].B);
        PlainsBmp.SetPixel(x, y, PlainsPixels[y * TileSize + x].R, PlainsPixels[y * TileSize + x].G, PlainsPixels[y * TileSize + x].B);
        MountainBmp.SetPixel(x, y, MountainPixels[y * TileSize + x].R, MountainPixels[y * TileSize + x].G, MountainPixels[y * TileSize + x].B);
    }
}

Then you can draw to the WorldBmp bitmap using normal Tile Map methods. IE, draw a mountain tile:
WorldBmp.SetPixels(x * TileSize, y * TileSize, MountainBmp.GetPixels());

I hope this is useful to someone :)

*Footnote: This actually took me an entire evening to write. No matter what I did, windows picture viewer would always report the bitmap was corrupt. In the end it turned out I had accidently opened the destination file as a text document and was writing in ASCII instead of binary - it probably worked first time. I'll admit to raging a little after that one. Then laughing.