Normally when I load textures in OpenGL, I have a PNG file which
I load into a System.Drawing.Bitmap and from there I pull out
the bytes and pass to glTexImage2D. It works, but seems a bit
silly having to create the bitmap in the first place. For this
reason, I was toying with the idea of creating a very simple
image format so I could just read the data directly without
requiring intermediate objects.
While mulling this idea over, I spotted an article on Hacker
News describing a similar and simple image format named
farbfeld. This format by suckless.org is described as
"a lossless image format which is easy to parse, pipe and
Not having much else to do on a Friday night, I decided I'd
write a C# encoder and decoder for this format, along with a
basic GUI app for viewing and converting farbfeld images.
"farbfeld" magic value
32-Bit BE unsigned integer (width)
32-Bit BE unsigned integer (height)
4x16-Bit BE unsigned integers [RGBA] / pixel, row-aligned
As you can see, it's about as simple as you can get, barring the
big-endian encoding I suppose. The main thing we have to worry
about is that farbeld stores RGBA values in the range 0-65535,
whereas in .NET-land we tend to use 0-255.
Decoding an image
Decoding an image is fairly straight forward. The difficult part
is turning those values into a .NET image in a fast manner.
Encoding an image
As with decoding, the difficult of encoding mainly lies in
getting the pixel data quickly. In this implementation, only
32bit RGBA images are supported. I will update it at some point
to support other colour depths (or at the very least add a hack
to convert lesser depths to 32bpp).
As you can see, it's a remarkably simple format and very easy to
process. However, it does mean that images tend to be large - in
my testing a standard HD image was 16MB for example. Of course,
as you'll probably be using this for some specific process
you'll be able to handle compression yourself.
After further reflection, I decided I wouldn't be using this
format as it wouldn't quite fit my OpenGL scenario, as OpenGL
(or at least the bits I'm familiar with) expect an array of
bytes, one per channel, unlike farbfeld which uses two (and the
larger value range as mentioned at the start). But I took the
source I wrote for farbfeld, refactored it to use single bytes
(and little-endian encoding for the other values), and that way
I could just do something like this
No System.Drawing.Bitmap, decoder class or complicated
The full source
The source presented here is abridged, you can get the full
version from the GitHub repository.