The first two filters are the simplest - None stores raw bytes, Sub stores each byte's difference from the pixel to its left. Today you reverse both, meeting the left-neighbor rule you will reuse everywhere.
Reconstruct a scanline filtered with type 0 (None) or type 1 (Sub).
None (filter type 0) is the identity: the row bytes are the pixel bytes, nothing to undo. Sub (type 1) stores each byte as its difference from the byte one pixel to the left, so to reconstruct you add back the already-reconstructed left neighbor: recon[x] = raw[x] + recon[x-bpp]. With bpp 1 and data 10, 5, 5, the first byte has no left neighbor so it stays 10, then 5 + 10 = 15, then 5 + 15 = 20.
Two rules recur through every filter. First, the left neighbor is the byte bpp positions back - one whole pixel, not one byte - so on RGBA you subtract from the same channel of the previous pixel. Second, when there is no neighbor (the first pixel of a row), that neighbor’s value is 0. And all arithmetic is modulo 256: bytes wrap, so 250 + 10 is 4. These three habits - reach back bpp, absent-is-zero, wrap at 256 - are the whole game for the filters ahead.
// recon[x] = raw[x] + recon[x-bpp], with recon[x-bpp] = 0 when x < bpp.// None (type 0): recon[x] = raw[x].// add modulo 256 (byte wraparound).func unSub(raw []byte, bpp int) []byte { }