The minimal bit writer from the DC-encode lesson packs bits but does not yet handle 0xFF or the final byte. Today you complete it with byte-stuffing and 1-bit padding, mirroring the decoder's bit reader.
Extend the bit writer so it stuffs a 0x00 after every 0xFF byte and pads the final partial byte with 1-bits on flush.
The bit writer already packs bits most-significant first from the DC-encode lesson; today it gains the two rules that make its output a legal scan, mirroring how the bit reader gained byte-stuffing a lesson after it was born. First: whenever a completed byte is 0xFF, the writer immediately appends a stuffed 0x00 so the decoder does not mistake it for a marker - writing eight 1-bits therefore emits FF 00, not just FF.
At the end of the scan the last byte is usually partial, and JPEG pads it with 1-bits - so writing just 010 and flushing yields 01011111 = 0x5F. Padding with 1s (rather than 0s) is deliberate: it can never accidentally form the start of a valid short code that a decoder would misread, and it matches what the restart-marker alignment expects. With the bit writer done, every entropy symbol and magnitude value has a place to go, and the encoder can produce a real scan. The remaining lessons write the surrounding markers and assemble the file.
// WriteBits from the DC-encode lesson already packs MSB-first; extend its// byte-completion step so that whenever a full byte is 0xFF it also appends// 0x00 (stuffing). Add Flush to pad the partial byte with 1-bits.// type BitWriter struct{ out []byte; cur byte; nbits int }func (w *BitWriter) WriteBits(value, n int) { /* + stuff on 0xFF */ }func (w *BitWriter) Flush() { /* pad partial byte with 1-bits */ }