NanoJPEG: a compact JPEG decoder

(April 29, 2009)

If you followed my works, you know that I like compact, single-file implementations of decoders for various media formats, and where such a thing doesn’t exist, I tend to write or at least port one myself. Now I’d like to add the third format to that list: Baseline JPEG images.

There are already two decoders on the web that go by the name »Tiny JPEG Decoder«: One of them actually isn’t tiny at all, it’s nothing but a huge load of C++ bloat. Luc Saillard’s decoder at least deserves its name somehow – I use it for my demo engine currently. It’s far from perfect, though – the color conversion code is awful, for example. It may be reasonably fast, but it’s bloated (dedicated conversion routines for every common format) and it lacks a proper chroma upsampling filter, resulting in ugly artifacts.

Since I was writing a JPEG decoder for work anyway, I decided to write another one at home, too. My goals were compact code, reasonable quality (read: a proper upscaling filter is a must-have) and decent, but not necessarily good speed. I think I have achieved that. Here are the bullet points:

  • decodes baseline JPEG only, no progressive or lossless JPEG
  • supports 8-bit grayscale and YCbCr images, no 16 bit, CMYK or other color spaces
  • supports any power-of-two chroma subsampling ratio
  • supports restart markers
  • the four points above mean that it should be able to decode all digital camera JPEG files and many other JPEG files
  • below 900 lines of code (and that already includes over 200 lines of comments and empty lines!)
  • converts YCbCr to RGB
  • uses a bicubic chrominance upsampling filter (this is actually better than the mere bilinear filter of libjpeg!)
  • a little slower than libjpeg
  • memory requirements: ~512 KiB (static) + 1x the decoded image size for grayscale images or 2x the decoded image size for color images
  • very simple API
  • input: memory dumps of JPEG files
  • output: memory dumps of raw, uncompressed 8-bit grayscale or 24-bit RGB pixels
  • output format is compatible to the PGM/PPM file formats as well as OpenGL GL_LUMINANCE8/GL_RGB8 texture formats
  • not fault-tolerant – any bitstream error will stop the decoder immediately and return an error to the application
  • 100% pure C code
  • no warnings with GCC 4.3 -pedantic and MSVC /W3
  • 32-bit integer arithmetic only
  • supposed to be endianness independent
  • 64-bit clean
  • not thread-safe
  • platform-independent
  • includes some provisions to build ultra-small Win32 executables
  • open source (free-beer, but maybe not really free-speech software)
  • single C file
  • batteries example program included

If you want to check it out, here is it:

nanojpeg.c

The code compiles to less than 6 kB of x86 code; with a suitable main() function that doesn’t use any C runtime library calls, it’s easily possible to create a 8 KiB Win32 executable that does what the built-in example program does: Decode a JPEG file to PGM or PPM. (Well, almost. The Win32-only version lacks error messages :) This can be reduced further by using Crinkler, and voilĂ : Here’s a working JPEG decompression program for Windows in just 4085 bytes:

nanojpeg.exe

(However, note that it only works properly when run from the command line!)

Ports to other programming languages

Other people have been busy porting NanoJPEG to other languages. Here is a list of all ports that have been contributed so far:

Finally, there’s my own port to (thread-safe) C and C++, called »µJPEG«, that adds a second bicubic chroma scaler for co-sited chroma samples (detected at runtime by examining the file’s Exif information), makes the scaler selectable at runtime and adds a »no decoding« mode where only the headers are examined to detect the image size.

Updates

2010-05-12: After a little delay of just (*cough*) two months, I updated nanojpeg.c to version 1.1. It fixes two compiler warnings with newer GCCs and, most importantly, a bug that caused NanoJPEG to reject valid files where the number of macroblocks is divisible by the restart interval – oops :)
Note that the new release is just an update of the C file, the example .exe file is still based on version 1.0.

2011-06-25: NanoJPEG now has an SVN repository: http://svn.emphy.de/nanojpeg/.

2012-02-18: Folkert van Heusden found and fixed a bug which caused NanoJPEG to generate syntax errors for valid streams that used 0xFFFF-style padding. The fix is incorporated in the updated version 1.2.

91 Responses to »NanoJPEG: a compact JPEG decoder«

Post a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Captcha: