Introducing the RGBA bitmap file format

.rgba is the dumbest possible image interchange format, for your programming pleasure.

So simple it fits on the back of an envelope.

TL;DR

Why this revolutionary idea?! and why now?

If you’re a programmer dealing with image or bitmap data, you’ll be familiar with the idea of the raw bitmap in memory, which these days is almost always one big, linear, RGBA, 4-byte-per-pixel buffer. You’ll be equally familiar with all the annoyances of getting this data to and from a file, the network, etc.

Why? Because although the bitmap in memory is super easy to work with, image files are all complicated, designed around the computing constraints and multifarious graphics hardware of the 1990s (!). Those standards all require you to pull in complex libraries and frameworks to work with them.

If you want to keep your code self-contained and simple there aren’t a lot of options. PNG and GIF are nontrivial; JPEG will make you run screaming. Even Microsoft’s BMP format, which is the nearest common format to “raw,” is a rat’s nest of accretive complexity once you start trying to parse it. Here is a handy diagram illustrating the different pixel subformats that BMP supports:

DON’T TRY THIS AT HOME FOLKS .Microsoft BMP format variants, via Wikipedia.

Who the f — needs to encode and decode 4 bit-per-pixel indexed palette RLE data in this futuristic year 2021? NO ONE. Disks are big and cheap, networks are fast. RGBA is fine, even if you’re only using a few colors!

So in some sense, .rgba is a spiritual successor to the Windows BMP — a distillation of its very essence into the single and minimal form that the vast majority of those files were using anyway.

Here is the spec for the file format:

  • 32-bit width (in pixels). Big-endian.
  • 32-bit height (in pixels). Big-endian.
  • Pixel data: 4 bytes per pixel, one byte each R, G, B, A. Always in that order. The bitmap starts at the upper-left of the image and scans each line, all the way to the bottom. There is no padding anywhere. The total length of the pixel data will be thus equal to width * height * 4 , and the formula for accessing the first byte (red channel) of any pixel will be: pixel_data[(y * width * 4) + (x * 4)]

The two numeric values, for the dimensions, are in big-endian byte order, also known as network byte order, also known as the one that’s easier to look at in a hex editor or memory dump.

I am providing a handy C module to conveniently save and load if you want to use that, but the format is so simple that you can do it in lots of different ways.

F.A.Q.s

What is the file extension for these files?

Won’t these files be huge?

Can I store the pixels in ARGB or BGRA order?

But once you introduce the option to have other orderings, you immediately end up with half the code that reads the files being incorrect or incomplete, so they mostly work, but not always, and then you might as well just be using the BMP format.

The point is clarity and simplicity and portability. You may need to transform the data slightly when reading or writing it. But since you’re already reading a large and uncompressed image, is that so much extra work? :)

Where does the other image metadata go?

How do I specify a color space? Don’t I need that?

My bitmaps don’t ever use transparency! Files are 33% too big!

Is the alpha channel premultiplied?

What about alignment?

(There are hypothetical cases where you might wish to load data directly into a buffer that benefits from 64-bit alignment. You can of course load the bitmap separately from the header fields and ensure your width is a multiple of two.)

How does .rgba beat the competition?

Who the hell are you?