I'm writing a tool to automate some of our asset making for a game. What I want to do is take a folder of PNG files, combine them into a texture atlas and then export the atlas as a TGA and the UV coords to XML.

I'm not sure which method I should use to load the PNG files in C# as there seem to be several. What is the recommended method to load images in C# that gives access to the colour/alpha data so I can extract it to the TGA?

I also already have TGA creation code in C++ which I plan to move to C# but I'm wondering if there is anything already available in .Net to create/save TGAs?

Thanks for reading.


I dont have a code sample, but i can give you a guideline

  1. Load PNG using Image.FromFile(). .NET supports loading PNG
  2. Open a file handle to your targa. Create an XmlDocument. .NET doesnt support targa, so you have to manually write it.
  3. Lock the bitmap to get at the pixels. GetPixel() is very slow. I think the method is named LockBits(). You get a pointer to the surface to read the pixels
  4. Write to targa. Targa is a container format, so any bitmap should fit.
  5. Save the UV as Xml.

Targa format

Do you want to use a palette ? Since your making a game, i would recommend you compute a palette for your bitmaps and put that into the targa to reduce the file size.

Oh , before i forget, .NET doesnt use RGBA, instead, the pixels are BGRA. Dont ask me why, but its like that.

Andrew Keith
+1  A: 

Loading a PNG file into a .Net Bitmap is easy:

Bitmap bmp = (Bitmap)Bitmap.FromFile("c:\wherever\whatever.png");
// yes, the (Bitmap) cast is necessary. Don't ask me why.

Once you have the Bitmap loaded, you can access all of its info (including alpha channel info) most efficiently using the Bitmap's LockBits method (there are many LockBits code samples on StackOverflow).

Update: here's a code sample that shows how to use LockBits to access the Bitmap's data pixel-by-pixel:

System.Drawing.Imaging.BitmapData data =
    bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
    System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
    // important to use the BitmapData object's Width and Height
    // properties instead of the Bitmap's.
    for (int x = 0; x < data.Width; x++)
        int columnOffset = x * 4;
        for (int y = 0; y < data.Height; y++)
            byte* row = (byte*)data.Scan0 + (y * data.Stride);
            byte B = row[columnOffset];
            byte G = row[columnOffset + 1];
            byte R = row[columnOffset + 2];
            byte alpha = row[columnOffset + 3];

You need to set the "Allow unsafe code" compiler option for your project to use this code. You could also use the GetPixel(x, y) method of the Bitmap, but this is amazingly slow.

The cast is necessary because Bitmap.FromFile doesn't actually exist -- it is calling the base class' static method Image.FromFile.
@bobbymcr: sure, but why doesn't Bitmap override FromFile, call base.FromFile and cast the returned Image as a Bitmap?