Quantization is where JPEG actually discards data - dividing each coefficient by a table value and rounding. Today you define the standard tables and quantize a block.
Define the standard luminance and chrominance quantization tables and quantize a coefficient block by rounding each coefficient divided by its table value.
Quantization is the lossy heart of JPEG. Each frequency coefficient is divided by a corresponding entry in a quantization table and rounded to the nearest integer, so 512/16 = 32 and -35/16 rounds to -2. The table values grow toward the high frequencies - the standard luminance table starts at 16 for DC and climbs to 99 - so fine detail is quantized coarsely and often rounds to zero, which is exactly what produces the long zero runs the entropy coder exploits.
The spec’s Annex K gives example tables for luminance and chrominance (chroma is quantized harder, its table starting at 17), and using them at their standard values corresponds to roughly quality 50. A real encoder scales these tables up or down for a quality setting, but fixed standard tables are a perfectly valid baseline choice and keep this project focused. Rounding is where the original data is irretrievably lost; everything after this is exact again, just as everything before dequantize was exact on the decode side. Next you reorder the quantized block into zig-zag sequence for entropy coding.
// standard tables from the JPEG spec (Annex K); quantize is round(coef/q).// both the coefficient block and the table are in natural order here.var StdLumaQuant = [64]int{16,11,10,16,24,40,51,61, 12,12,14,19, /* ... */}func quantize(coef [64]float64, q [64]int) (out [64]int) { }