Reverse Engineering the JD11 - A drama in n chapters


What is the JD11?

The JD11 is a cheap digital camera produced by JenOptik (apparenly a subsidary of Zeiss Jena). It was at the time of writing this available for around 250 DM.

There is software available, a windows program called FotoBee which is a huge heap of MFC dung. It can be made to run with a small hack under the free Windows Emulator WINE.

WINE was crucial in reverse engineering the camera at all stages of the project.

Chapter 1:The lowlevel serial protocol

The JD11 comes with a serial cable with a DB9 connector on the computerside and a small klinkenstecker at the camera end. So just 2 lines (RX, TX) and GND.

There is no documenation on the serial protocol in the inlaying documentation.

The FotoBee.exe program uses the Windows serial communications interface, which is fortunately implemented in WINE. By snooping the setup calls, the serial parameters are:

        115200 Baud, no parity, 1 stopbit, 8 bit data, no flow control
        (neither crtscts, nor XON/XOFF)
It also setting some large timeouts, since the camera sometimes needs like 2 seconds to think about something.

That was rather trivial.

Chapter 2: The serial data transfer protocol

The next step was to find out how the FotoBee software talks to the camera.

 Luckily the program still uses the standard Win32 serial communication functions for that, so I added some code to the ReadFile and WriteFile functions, which dumps the read/written buffer if it is writing to a serial device.

In general, the program sends a command down the serial line (with optional arguments) and receives data back. Every command starts with a 0xFF character.
CommandArgumentsReturnsDescription
0xff 0x08 None 0xff 0xf1 Ping!s the camera.
0xff 0xa7 None Between 10 and 20 bytes 3 float factors are returned, they are calculated:
f1=r[1]+r[2]*0.1+r[3]*0.01;
f2=r[4]+r[5]*0.1+r[6]*0.01;
f3=r[7]+r[8]*0.1+r[9]*0.01;

Their use is still unknown to me.
0xff 0xa4 None 0xff 0x01 Select Index Picture to transfer, is followed by packetreading
0xff 0xa1 0xff picturenr 0xff 0x01 Selects Image picturenr to transfer. 3 Bytestreams follow (packetreading has to be called 3 times)
0xff 0xf0 None Returns an ASCII hexnumber (starting with two 0x66 ('f')) Returns the size (in bytes) of the image to transfer next. This command is issued after "select index" or "select image" and is followed by (multiple) packet reads.
0xff 0xf1 None Returns 201 or less bytes The packetreader. It is called in a loop after querying the imagesize. If 201 bytes are read, the 201th byte is the checksum (sum of 0-199)&0xff, otherwise there is no checksum.
Returns the 200 bytes read.
0xff 0xf3 None Returns 201 or less bytes The packet resend command. Works exactly like the 0xff 0xf1 packetread command, but the last packet is retransmitted. This is useful for corrupted transmissions.
0xff 0x79 None 0xff 0xXX Function unknown, seems to open/close the shutter in rapid succession.
0xff 0x73 None 0xff 0xXX Function unknown
0xff 0x72 None 0xff 0xXX Function unknown
0xff 0x75 None 0xff 0xXX Function unknown

Following commands can be used on toplevel:

For reading the INDEX picture following sequence appears: For reading the IMAGE picture following sequence appears: Thats all we needed to know about the serial commands.

Chapter 3: The image compression, stage 1

Judging from other cameras it is easy to suspect the camera uses the JPEG format. It does not unfortunately.

Chapter 3.1: The format of the index picture

Casting a closer look at the raw data of the index picture shows a a stream of 8 bit values. Some experimentation later it turns out to a stream of 64x48 grayscale pictures, upside down. Using:
	rawtopgm <index 64 (sizeof_index/64) |pnmflip -tb > index.ppm
we can convert it into a .PPM and convert it further using standard UNIX tools.

The size of the index picture also tells us the number of pictures that are currently stored in the camera. Just divide the size of the indeximage by 64*48.

Chapter 3.2: The low quality compressed image format

The camera has two modes to store pictures, either in low or high quality. This is marked by the letters "L" and "H" on the cameras LCD. Default is the low quality format.

It is still unclear to me how to detect high/low quality formats, except with the size of the returned image.

At first look the data returned from the camera looks like junknoise. So I had to peek into the diassembly, which shows a slightly inefficient huffman decompressor, with following bitpatterns:
BitsValue
00 -2
01 6
10 2
110 6
1110 11
1111 0 -11
1111 10 20
1111 110 -20
1111 1110 45
1111 1111 0 -45
1111 1111 10 90
1111 1111 110 -90
1111 1111 1110 180
1111 1111 1111 0 -180
The result of this decompression run is 320*480 bytes for the first image, and 320*240 for the second and third image. But these are not the pixel values, these are differences!
So I had another look. Pixels are 8bit unsigned values and computed like this:

Tada. We now have 3 uncompressed images, the first 320x480, the others 320x240.

Chapter 3.2: The high quality compressed image format

The high quality format uses a very different compression.

It just compacts all 8bit values to 6bit by shortening out the 2 least significant bits. So we just restore them (AAAA AABB BBBB CCCC CCDD DDDD -> AAAAAA00, BBBBBB00, CCCCCC00, DDDDDD00) and get the same grayscale images as with the lowquality compression.

Chapter 3.3: Getting the final images

The final image has the following components: The merged image now just has to be mirrored vertical and horizontal and we are done. Mostly.
The resulting image itself needs a smoothing pass (due to the blowup above), but this can be done with any image manipulation program.