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
compress".
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.
The format
Bytes
Description
8
"farbfeld" magic value
4
32-Bit BE unsigned integer (width)
4
32-Bit BE unsigned integer (height)
[2222]
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).
Nothing complicated
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
decoding required!
The full source
The source presented here is abridged, you can get the full
version from the GitHub repository.
Update History
2016-01-19 - First published
2017-03-04 - Corrected divisor
2020-11-21 - Updated formatting
Like what you're reading? Perhaps you like to buy us a coffee?
Please note, that your conversion to and from 16bit RGBA is not completely correct. To span the full range of 2^16 values in the unisgned integer of farbfeld, you would need to multiply or divide by 257 instead of 256 since the maximum value in an 8 bit integer is 255 and NOT 256. If you look at the implementation at suckless.org for reference, this is done exactly that way.
The founder of Cyotek, Richard enjoys creating new blog content for the site. Much more though, he likes to develop programs, and can often found writing reams of code. A long term gamer, he has aspirations in one day creating an epic video game - but until that time comes, he is mostly content with adding new bugs to WebCopy and the other Cyotek products.
# mseeber
# Richard Moss