Decoding of Nikon raw format (NEF)

I'm working on a project where I need the raw values of the Bayer matrix of the sensor. I'm using a Nikon D7500, which saves raw images in NEF. I'm currently at a point where I'd love to have some more info on a few things. I'm asking here in case some people in the Rust community are also image format experts.

NEF is basically a TIFF 6 file with some tags specific to Nikon. For now, I've extracted the &[u8] slice corresponding to the compressed strip of the image lines and would like to decompress it. My images are lossless compressed, with an algorithm specific to Nikon (compression = 34713) based on Huffman trees and quantization. From what I've read here (http://lclevy.free.fr/nef/) the data required for the Huffman decoding is in the Maker Note of the file. So I've decoded the maker note entries, notably tag 0x93 (147) which confirms that it is lossless compression (3). Now I'm a little bit lost regarding where exactly I can retrieve the Huffman table to proceed to decompression of the strip.

The code in dcraw regarding NEF decompression is a little bit obscure to me so any help to better understand the format is welcomed!

If everything works, I'd love to publish the resulting NEF decoder as a crate in case that's useful to others.

I've added below the content of the maker note in case that's useful.

Maker note head: [78, 105, 107, 111, 110, 0, 2, 17, 0, 0]
Maker note byte order: LittleEndian
Number of entries: 74
Next IFD offset: 0
DirectoryEntry { tag: 1, type_: 7, count: 4, value_or_offset: [48, 50, 49, 49] }
DirectoryEntry { tag: 4, type_: 2, count: 8, value_or_offset: [134, 3, 0, 0] }
DirectoryEntry { tag: 5, type_: 2, count: 13, value_or_offset: [142, 3, 0, 0] }
DirectoryEntry { tag: 7, type_: 2, count: 7, value_or_offset: [158, 3, 0, 0] }
DirectoryEntry { tag: 8, type_: 2, count: 13, value_or_offset: [166, 3, 0, 0] }
DirectoryEntry { tag: 9, type_: 2, count: 20, value_or_offset: [182, 3, 0, 0] }
DirectoryEntry { tag: 11, type_: 8, count: 2, value_or_offset: [0, 0, 0, 0] }
DirectoryEntry { tag: 12, type_: 5, count: 4, value_or_offset: [202, 3, 0, 0] }
DirectoryEntry { tag: 13, type_: 7, count: 4, value_or_offset: [0, 1, 6, 0] }
DirectoryEntry { tag: 14, type_: 7, count: 4, value_or_offset: [1, 1, 12, 0] }
DirectoryEntry { tag: 17, type_: 4, count: 1, value_or_offset: [174, 153, 0, 0] }
DirectoryEntry { tag: 18, type_: 7, count: 4, value_or_offset: [0, 1, 6, 0] }
DirectoryEntry { tag: 23, type_: 7, count: 4, value_or_offset: [0, 1, 6, 0] }
DirectoryEntry { tag: 24, type_: 7, count: 4, value_or_offset: [0, 1, 6, 0] }
DirectoryEntry { tag: 25, type_: 10, count: 1, value_or_offset: [234, 3, 0, 0] }
DirectoryEntry { tag: 27, type_: 3, count: 7, value_or_offset: [242, 3, 0, 0] }
DirectoryEntry { tag: 28, type_: 7, count: 3, value_or_offset: [0, 1, 6, 0] }
DirectoryEntry { tag: 29, type_: 2, count: 8, value_or_offset: [2, 4, 0, 0] }
DirectoryEntry { tag: 30, type_: 3, count: 1, value_or_offset: [1, 0, 0, 0] }
DirectoryEntry { tag: 31, type_: 7, count: 8, value_or_offset: [10, 4, 0, 0] }
DirectoryEntry { tag: 34, type_: 3, count: 1, value_or_offset: [0, 0, 0, 0] }
DirectoryEntry { tag: 35, type_: 7, count: 68, value_or_offset: [18, 4, 0, 0] }
DirectoryEntry { tag: 36, type_: 7, count: 4, value_or_offset: [60, 0, 1, 2] }
DirectoryEntry { tag: 37, type_: 7, count: 14, value_or_offset: [86, 4, 0, 0] }
DirectoryEntry { tag: 42, type_: 3, count: 1, value_or_offset: [3, 0, 0, 0] }
DirectoryEntry { tag: 43, type_: 7, count: 16, value_or_offset: [102, 4, 0, 0] }
DirectoryEntry { tag: 44, type_: 7, count: 574, value_or_offset: [118, 4, 0, 0] }
DirectoryEntry { tag: 59, type_: 5, count: 4, value_or_offset: [182, 6, 0, 0] }
DirectoryEntry { tag: 60, type_: 3, count: 1, value_or_offset: [1, 0, 0, 0] }
DirectoryEntry { tag: 61, type_: 3, count: 4, value_or_offset: [214, 6, 0, 0] }
DirectoryEntry { tag: 62, type_: 3, count: 1, value_or_offset: [1, 0, 0, 0] }
DirectoryEntry { tag: 63, type_: 10, count: 2, value_or_offset: [222, 6, 0, 0] }
DirectoryEntry { tag: 64, type_: 7, count: 12, value_or_offset: [238, 6, 0, 0] }
DirectoryEntry { tag: 65, type_: 7, count: 6, value_or_offset: [250, 6, 0, 0] }
DirectoryEntry { tag: 66, type_: 7, count: 6, value_or_offset: [2, 7, 0, 0] }
DirectoryEntry { tag: 67, type_: 7, count: 12, value_or_offset: [10, 7, 0, 0] }
DirectoryEntry { tag: 68, type_: 3, count: 1, value_or_offset: [0, 0, 0, 0] }
DirectoryEntry { tag: 69, type_: 3, count: 4, value_or_offset: [22, 7, 0, 0] }
DirectoryEntry { tag: 70, type_: 3, count: 2, value_or_offset: [0, 0, 0, 0] }
DirectoryEntry { tag: 71, type_: 7, count: 12, value_or_offset: [30, 7, 0, 0] }
DirectoryEntry { tag: 73, type_: 7, count: 12, value_or_offset: [42, 7, 0, 0] }
DirectoryEntry { tag: 76, type_: 7, count: 32, value_or_offset: [54, 7, 0, 0] }
DirectoryEntry { tag: 77, type_: 7, count: 84, value_or_offset: [86, 7, 0, 0] }
DirectoryEntry { tag: 78, type_: 7, count: 1008, value_or_offset: [170, 7, 0, 0] }
DirectoryEntry { tag: 131, type_: 1, count: 1, value_or_offset: [14, 0, 0, 0] }
DirectoryEntry { tag: 132, type_: 5, count: 4, value_or_offset: [154, 11, 0, 0] }
DirectoryEntry { tag: 135, type_: 1, count: 1, value_or_offset: [0, 0, 0, 0] }
DirectoryEntry { tag: 137, type_: 3, count: 1, value_or_offset: [0, 0, 0, 0] }
DirectoryEntry { tag: 138, type_: 3, count: 1, value_or_offset: [1, 0, 0, 0] }
DirectoryEntry { tag: 139, type_: 7, count: 4, value_or_offset: [71, 1, 12, 0] }
DirectoryEntry { tag: 140, type_: 7, count: 578, value_or_offset: [186, 11, 0, 0] }
DirectoryEntry { tag: 145, type_: 7, count: 18271, value_or_offset: [254, 13, 0, 0] }
DirectoryEntry { tag: 147, type_: 3, count: 1, value_or_offset: [3, 0, 0, 0] }
DirectoryEntry { tag: 149, type_: 2, count: 5, value_or_offset: [94, 85, 0, 0] }
DirectoryEntry { tag: 150, type_: 7, count: 46, value_or_offset: [102, 85, 0, 0] }
DirectoryEntry { tag: 151, type_: 7, count: 2468, value_or_offset: [150, 85, 0, 0] }
DirectoryEntry { tag: 152, type_: 7, count: 33, value_or_offset: [58, 95, 0, 0] }
DirectoryEntry { tag: 153, type_: 3, count: 2, value_or_offset: [240, 10, 72, 7] }
DirectoryEntry { tag: 158, type_: 3, count: 10, value_or_offset: [94, 95, 0, 0] }
DirectoryEntry { tag: 163, type_: 1, count: 1, value_or_offset: [0, 0, 0, 0] }
DirectoryEntry { tag: 164, type_: 7, count: 4, value_or_offset: [48, 51, 48, 48] }
DirectoryEntry { tag: 167, type_: 4, count: 1, value_or_offset: [247, 17, 0, 0] }
DirectoryEntry { tag: 168, type_: 7, count: 163, value_or_offset: [114, 95, 0, 0] }
DirectoryEntry { tag: 171, type_: 2, count: 16, value_or_offset: [22, 96, 0, 0] }
DirectoryEntry { tag: 176, type_: 7, count: 16, value_or_offset: [38, 96, 0, 0] }
DirectoryEntry { tag: 177, type_: 3, count: 1, value_or_offset: [2, 0, 0, 0] }
DirectoryEntry { tag: 182, type_: 7, count: 8, value_or_offset: [54, 96, 0, 0] }
DirectoryEntry { tag: 183, type_: 7, count: 84, value_or_offset: [62, 96, 0, 0] }
DirectoryEntry { tag: 184, type_: 7, count: 172, value_or_offset: [146, 96, 0, 0] }
DirectoryEntry { tag: 185, type_: 7, count: 4, value_or_offset: [0, 255, 0, 0] }
DirectoryEntry { tag: 187, type_: 7, count: 8, value_or_offset: [62, 97, 0, 0] }
DirectoryEntry { tag: 188, type_: 7, count: 14430, value_or_offset: [70, 97, 0, 0] }
DirectoryEntry { tag: 191, type_: 3, count: 1, value_or_offset: [0, 0, 0, 0] }
DirectoryEntry { tag: 192, type_: 7, count: 8, value_or_offset: [166, 153, 0, 0] }
3 Likes