Taco de Wolff
JPEG file format
This articles provides information on how a JPEG file is constructed at binary level. It is accompanied with this article: JPEG scan data. The conversion from a raw bitmap to JPEG is implemented in this tool: JPEG
General structure
The JPEG file format uses markers to denote the beginning of a certain block. These markers are 2 bytes long and start with 0xFF
followed by the marker for the following block. This consequently means that if we were to write a 0xFF
that does not denote the beginning of a block, we must escape it by appending 0x00
right after the 0xFF
. This means that no block is following and only the 0xFF
is interpreted as being part of the data.
Markers and segments
The following segments are discussed in the order they’d appear in a basic JPEG file. Some are optional segments and some optional segments are left out of the discussion. If you were to decode a JPEG file, you can often skip those optional segments.
Start Of Image
`0xFF 0xD8` MarkerAPP0
`0xFF 0xE0` Marker `0x?? 0x??` Segment length is the length of the segment excluding the marker `0x4A46494600` Reads JFIF `0x01 0x02` Version 1.2 `0x00` No density units used (defaults to 72 DPI I believe) `0x00 0x01` Scaling of 100% in the X direction (no scaling) `0x00 0x01` Scaling of 100% in the Y direction (no scaling) `0x00 0x00` Width and height of thumbnail are zeroQuantization table
Usually two tables are provided, one for the luminance and one for the chrominance. See bottom of the page for the default quantization tables. The elements must be provided in the serpentine / zigzag order.
`0xFF 0xDB` Marker `0x00 0x43` Segment length is the length of the segment excluding the marker (3 + 64) `0x0?` Insignificant four bits denote the table ID, significant four the precision of its elements (set to 0 for default 8bit per element) `...` 64 values of the quantization tableStart Of Frame
`0xFF 0xC0` Marker `0x00 0x11` Segment length is the length of the segment excluding the marker (17 for us) `0x08` Precision of 8bits `0x?? 0x??` Height of image in 2 bytes `0x?? 0x??` Width of image in 2 bytes `0x03` Three color components `0x01 0x11 0x??` Component 1 (luminance), 1x1 sample (no subsampling), quantization table ID `0x02 0x11 0x??` Component 2 (chrominance blue) `0x03 0x11 0x??` Component 3 (chrominance red)Huffman table
Usually four tables are provided, two for the luminance and two for the chrominance. Each is split into tables for DC and AC values. See bottom of the page for the default Huffman tables and see JPEG scan data for an explanation to use it.
`0xFF 0xC4` Marker `0x?? 0x??` Segment length is the length of the segment excluding the marker (3 + 16 + X) `0x??` Insignificant four bits denote the table ID, the 5th bit is true for AC and false for DC `...` 16 values for the bit lengths `...` X values for the codesStart of Scan
Multiple scans may exist for interlacing. We use only one.
`0xFF 0xDA` Marker `0x00 0x0C` Segment length is the length of the segment excluding the marker and scan data (12) `0x03` Three color components `0x01 0x??` Component 1 (luminance), huffman table ID `0x02 0x??` Component 2 (chrominance blue) `0x03 0x??` Component 3 (chrominance red) `0x00 0x3F 0x00` Skipping three bytes (no idea what the `0x3F` is for...) `...` Entropy-encoded scan data, see JPEG scan dataEnd Of Image
`0xFF 0xD9` MarkerDefault quantization tables
/* Luminance */
const uint8_t Qy_[] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
/* Chrominance */
const uint8_t Qc_[] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
Default Huffman tables
/* Luminance DC */
const uint8_t Hy_dc_bits[] = {
0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
};
const uint8_t Hy_dc_val[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
};
/* Luminance AC */
const uint8_t Hy_ac_bits[] = {
0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
};
const uint8_t Hy_ac_val[] = {
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
/* Chrominance DC */
const uint8_t Hc_dc_bits[] = {
0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
};
const uint8_t Hc_dc_val[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
};
/* Chrominance AC */
const uint8_t Hc_ac_bits[] = {
0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
};
const uint8_t Hc_ac_val[] = {
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
More information: http://class.ee.iastate.edu/ee528/Reading%20material/JPEG_File_Format.pdf