The BITS counts and symbol list determine every code's exact bit pattern by a fixed rule. Today you assign those canonical codes, turning a table description into something you can decode with.
Assign a canonical Huffman code (a bit pattern and length) to each symbol from the BITS counts.
JPEG Huffman codes are canonical, meaning the BITS counts and symbol order pin down every bit pattern with no ambiguity. The rule: walk lengths from 1 to 16, keep a running code value, hand it to the next symbol of the current length and increment, and when you move to the next length, shift code left by one. Because there are no 1-bit codes here, the first real code is the 2-bit 00 for symbol 0; the five 3-bit codes are 010, 011, 100, 101, 110 for symbols 1 through 5; then the 4-bit 1110 for symbol 6, and so on.
Deriving codes this way, rather than storing them, is what keeps the table description tiny. The (code, length) pairs you produce are the decode table: given a run of bits, you accumulate them and check whether the value so far matches a code of the current length. That accumulate-and-match loop is the next chapter’s job; today you have turned a compact description into the concrete codes it stands for.
// canonical assignment (T.81 Annex C):// code := 0// for length 1..16:// for each symbol of this length (HUFFVAL order): assign code; code++// code <<= 1 // step to the next length// store (code, length) per symbol, indexed for decode.func buildCodes(counts [16]int, syms []byte) { }