A Bitmap Library

(The source code of which is on Github)

I thought it is about time to write something about my library of C functions for manipulating bitmap images. It has been with me for many years and I've used it in a lot of my hobby projects.

So here I will give a broad overview of the library and then I might write more about the specific points of interest at a later date.

Supported File Formats

The origins of bmp.c was modest. I originally wanted only a chunk of C code that could take a buffer containing an image and write it to a Windows BMP file.

Seeing as I was now able to read from a BMP file, it wasn't much of a stretch to add the ability to write them as well. From there I kept on adding support for other file formats, like PNG, JPEG, GIF, PCX and TGA until evolved into the 4000+ line behemoth I present here today.

GIF Support

The most complicated part of the library was the saving and loading of GIF images.

A GIF file contains several blocks, and each of those blocks can contain a structure with flags that might describe the blocks that follow, or palette information, or LZW compressed data blocks.

Fortunately the GIF specification is well written, so I managed to implement my encoder and decoder in a finite amount of time. Implementing the LZW compression/decompression was probably the most interesting part of the endeavour. I had to reference some other sources to explain everything; you'll find the links in the source code.

The only time I bumped my toe was when I couldn't get animated GIFs to animate. The problem turned out to be that I missed the Netscape Application Block (NAB), because it is not part of the GIF89 spec. Wikipedia describes it in detail, so when I found it I got animated GIFs working quite quickly.

I actually started my GIF encoder/decoder in a separate source file where I implemented the specification as completely as possible. You'll find that implementation in misc/gif.c (and misc/gif.h).

The implementation in bmp.c was then stripped of anything that wasn't needed. For example, bm_load() only returns a single Bitmap object so it only bothers with the first frame of animated GIFs, and bm_save() doesn't allow any customization when saving a file, so it just chooses sensible defaults.

If you want more control over how your GIFs are saved and loaded, I invite you to look at the GIF-related files in the misc/ directory. They implement the spec more completely, and provides support for animated GIFs and so on.

XBM and XPM support

If, like me, you've grown up with Windows, these two file formats would seem a bit esoteric.

X Bitmap(XBM) images are encoded as valid C source code files, the content of which defines an array of bytes, each byte representing 8 monochrome pixels.

So a file test.xbm may look like this (from Wikipedia):

#define test_width 16
#define test_height 7
static char test_bits[] = {
0x13, 0x00, 0x15, 0x00, 0x93, 0xcd, 0x55, 0xa5, 0x93, 0xc5, 0x00, 0x80, 
0x00, 0x60 };

You would #include "test.xbm" in your source files to have the image compiled into your program. With this particular example you would call Bitmap *img = bm_from_Xbm(test_width, test_height, test_bits) to get a bitmap object for use in your program.

I implemented support for XBM because I liked the idea of compiling graphic resources into my programs so that the executable can be distributed without any additional files.

I later added support for X PixMap(XPM) images. These are also encoded as C source code.

This is an example from Wikipedia:

/* XPM */
static char * XFACE[] = {
/* <Values> */
/* <width/cols> <height/rows> <colors> <char on pixel>*/
"48 4 2 1",
/* <Colors> */
"a c #ffffff",
"b c #000000",
/* <Pixels> */
"abaabaababaaabaabababaabaabaababaabaaababaabaaab",
"abaabaababaaabaabababaabaabaababaabaaababaabaaab",
"abaabaababaaabaabababaabaabaababaabaaababaabaaab",
"abaabaababaaabaabababaabaabaababaabaaababaabaaab"
};

You would then just call Bitmap *img = bm_from_Xpm(XFACE); in your code and you're off.

What I like about this format is that you can basically add images to your programs in almost the same way that you would add string and numeric literals, and you can manipulate the pictures with nothing more than a text editor. They are also in colour, and have all the advantages of XBM images as well.

Other File Types

The PCX and TGA file formats are a bit old fashioned, but I've run into them on a couple of places on the internet (specifically, older OpenGL tutorials).

Both formats are fairly straightforward, and there are lots of resources on the internet for how they work. Both of them uses Run-length encoding for compression, so once I implemented the PCX reader and writer, the TGA code was quite simple.

I also wanted support for JPEG and PNG, but in this particular case I didn't want to reinvent the wheel, so I implemented support for libjpeg and libpng to save and load those file types respectively.

The misc/pbm.c file in the distribution is a parser for the Netpbm image formats.

The Netpbm file formats all store images as ASCII text files and were created for early email systems where transferring binary files was difficult.

They are larger than the equivalent binary files would be, and aren't that common today, but they can still be useful. I have one particular example where I created a Java program that ran on a server without a GUI, but having a graphical representation of its internal states would've been helpful in troubleshooting. In this case I generated several PBM files as the program ran, and then converted them to GIFs on my own computer afterwards.

Image Manipulation

Naturally, once you have an image in memory, you'd want to manipulate it.

I support drawing lines through Bresenham's line algorithm, drawing rectangles, circles, ellipses and bezier curves. I also provide a flood fill function to colour the image.

There are also several functions to blit (copy) one Bitmap to another. All of them takes a region of a source image and copies them to a destination. The main difference between these is whether the function uses a mask colour to hide the background or not. Games and so on will probably use the background mask.

The bm_blit_ex() function is probably the most interesting of these because the region on the destination doesn't need to be the same size as on the source, in which case the image is stretched to fit into the destination region. It actually uses Bresenham's algorithm again to do this efficiently.

There are also several functions to manipulate colors. One of my personal favourites is bm_atoi() that takes a string and parses it into a colour. The parser took inspiration from the way colours are specified in CSS: It supports colour names like "red" (based on the web colours), hex colours like "#00FF00", and the "RGB(255,0,0)" and "HSL(0,100%, 50%)" formats.

The library also has functions to manipulate the RGB, HSL and alpha values of colours and interpolate between colours.

Rendering Text

There are a couple of ways to render text using the module.

Originally, I supported rendering only 8x8 bitmapped characters, which was fine because at the time the main purpose of the library was to support a retro-style game engine I was developing at the time.

The 8x8 character fonts were stored as XBM files, as described above, and then blitted to the bitmap in the bm_puts() and related functions.

At some point I started feeling that this was a bit limiting, so I abstracted the text rendering away into a structure called BmFont that has pointers to functions that know how to render the text.

This new abstraction allowed me to add support for rendering text through FreeType fonts. There is nothing particularly complex about my implementation: the files in the ftypefont/ subdirectory of the distribution gives you a set of functions that creates and destroys the BmFont objects that wrap around FreeType objects, from where you can use the normal bm_puts() and related functions to render text onto the bitmap.

Other

I've implemented functions over the years to apply several other manipulations to images:

Back-Ends

The library has a function called bm_bind() that wraps the Bitmap object around an array of bytes that represents an image in memory.

It requires that the array of bytes be in a specific format (ARGB, specifically). Fortunately it is a very common format on modern computers, so the library can be used to manipulate a wide variety of graphics:

A neat consequence of supporting SDL is that it also works in a Web browser if you use emscripten to compile your program to a web application.

There was one problem: the canvas as used by emscripten has its pixels in the ABGR format. I've had to add ABGR preprocessor directive that swaps the R and B channels (so you add -DABGR=1 in the CFLAGS -see for example emscripten.mak file in the abovementioned Chip-8 emulator).

It works, but there might still be some lurking bugs since I don't use it that often.

I've also played around with using Cairo graphics to draw onto the Bitmap object (see the misc/cairoback.c file in the distribution). Cairo already supports a wide variety of back-ends, though, so I can't actually think of a use case where this library would be useful if you're already pulling in Cairo into your software.

Conclusion

I've found it very useful to have a bitmap module that I can just copy and paste into a new directory whenever I start with a hobby project where I want to play around with bitmapped graphics.

I'll be the first to admit that it could be optimized in many areas, and I really try to improve it as I go along.

Yet, shying away from platform specific optimizations and keeping the code clean has had the benefit of keepiing the library portable and flexible. I've used it under Windows and Linux and in web browsers (through emscripten); It has worked with OpenGL textures, SDL surfaces and Win32 GDI handles. I've also seen it working on Android (through the SDL surfaces and the NDK). The API has also stabilized over the years and it has become quite robust.

As mentioned already, the source code is on Github.