~/bend-docscommunity

src/jpeg_enc.bend checks

raw source on the hub · import 0x83c5c81fb41f55ca634bdc7bde39a51b/src/jpeg_enc.bend as Jpeg_enc

src/jpeg_enc: baseline JPEG encode. Sequential 8-bit Huffman (SOF0) and JFIF APP0. Colour is 4:4:4 YCbCr, no subsampling: one 8 by 8 block per component per MCU. Samples are packed 0xAARRGGBB, the layout decode returns; the alpha byte is ignored. Quantisation steps are all 1, so an integer coefficient is kept whole. The forward DCT (T.81 A.3.3) pairs samples that share a cosine weight, then rounds once with the same fixed-point product as a matrix column. Both components share the Annex K luminance Huffman tables. A coefficient indexes its symbol. The scan does not walk the table. A mixed MCU reads each pixel once and keeps the three level planes in arrays. Quant steps are 1, so the mixed scan emits coefficients without dividing. A neutral solid (R = G = B = 128) is an all-zero block and round-trips exactly. Other colours are lossy. Progressive and arithmetic frames are not written. Width and height must sit in 1..65535; anything else is SOI then EOI.

2 imports
import Base
import ./jpeg.bend as Jpeg

Types

type Put source · line 19 · raw

Data

bytes emitted so far (newest first), the open byte, and how many bits it holds

type Kern source · line 23 · raw

Data

cosine weights shared by symmetric samples: DC, two even weights, four odd weights

type Ctx source · line 27 · raw

Data

the cosine kernel, zigzag, and the all-ones quant table

type Book source · line 31 · raw

Type

DC and AC symbols indexed to a packed code: length in the high half, code in the low half

type Code source · line 35 · raw

Data

one looked-up Huffman code

type Oct source · line 39 · raw

Data

eight values, the first at frequency 0

type Planes source · line 43 · raw

Type

the sample plane, the frequency plane, and the next column of one forward DCT

type Tile source · line 47 · raw

Type

one MCU: packed pixels, three level planes, and whether each plane is the neutral level

type Scan source · line 51 · raw

Type

frequency plane, the open zero run, and the AC coder. Steps are 1, so no quant list.

Definitions

def encode.join source · line 54 · raw

@aa:List<&2, U32> -> @bb:List<&2, U32> -> List<&2, U32>

def encode.len source · line 57 · raw

@xs:List<&2, U32> -> U32

def encode.seg source · line 60 · raw

@+mark:U32 -> @+body:List<&2, U32> -> List<&2, U32>

def encode.app0 source · line 64 · raw

List<&2, U32>

def encode.quant source · line 67 · raw

List<&2, U32>

def encode.dqt source · line 70 · raw

List<&2, U32>

def encode.sofbody source · line 73 · raw

@+ww:U32 -> @+hh:U32 -> List<&2, U32>

def encode.sof source · line 76 · raw

@+ww:U32 -> @+hh:U32 -> List<&2, U32>

def encode.dccounts source · line 79 · raw

List<&2, U32>

def encode.dcsyms source · line 82 · raw

List<&2, U32>

def encode.accounts source · line 85 · raw

List<&2, U32>

def encode.acsyms source · line 88 · raw

List<&2, U32>

def encode.dht source · line 97 · raw

@+cls:U32 -> @+counts:List<&2, U32> -> @+syms:List<&2, U32> -> List<&2, U32>

def encode.sos source · line 100 · raw

List<&2, U32>

def encode.header source · line 103 · raw

@+ww:U32 -> @+hh:U32 -> @+dcc:List<&2, U32> -> @+dcs:List<&2, U32> -> @+acc:List<&2, U32> -> @+acs:List<&2, U32> -> List<&2, U32>

def encode.kern source · line 115 · raw

@+cs:List<&2, U32> -> Kern

C[0][0], C[0][2], C[0][6], and the first four weights of frequency 1

def encode.kern.drop source · line 119 · raw

@kern:Kern -> U32

def encode.ctx source · line 131 · raw

Ctx

def encode.word source · line 135 · raw

@+len:U32 -> @+code:U32 -> U32

length sits above the 16-bit code

def encode.bad.b source · line 138 · raw

@bw:Bool -> @bh:Bool -> Bool

def encode.bad.h source · line 145 · raw

@zz:Bool -> @bw:Bool -> @bh:Bool -> Bool

def encode.bad.w source · line 152 · raw

@zz:Bool -> @zh:Bool -> @bw:Bool -> @bh:Bool -> Bool

def encode.bad source · line 159 · raw

@+ww:U32 -> @+hh:U32 -> Bool

def encode.put0 source · line 162 · raw

Put

def encode.stuff.ff source · line 165 · raw

@ff:Bool -> @out:List<&2, U32> -> @+bb:U32 -> Put

def encode.stuff source · line 172 · raw

@out:List<&2, U32> -> @+bb:U32 -> Put

def encode.bit.n source · line 175 · raw

@full:Bool -> @out:List<&2, U32> -> @+nb:U32 -> @+nn:U32 -> Put

def encode.bit source · line 182 · raw

@pp:Put -> @+bit:U32 -> Put

def encode.bits.go source · line 187 · raw

@left:Nat -> @pp:Put -> @+code:U32 -> Put

def encode.bits source · line 195 · raw

@pp:Put -> @+len:U32 -> @+code:U32 -> Put

def encode.pad.byte source · line 198 · raw

@ff:Bool -> @out:List<&2, U32> -> @+byte:U32 -> List<&2, U32>

def encode.pad.n source · line 205 · raw

@zz:Bool -> @out:List<&2, U32> -> @+buf:U32 -> @+nn:U32 -> List<&2, U32>

def encode.pad source · line 215 · raw

@pp:Put -> List<&2, U32>

def encode.drop source · line 220 · raw

@xs:List<&2, U32> -> U32

def encode.fill source · line 224 · raw

@syms:List<&2, U32> -> @codes:List<&2, U32> -> @lens:List<&2, U32> -> @aa:Array<U32> -> Array<U32>

one canonical table, stored so the symbol is the index

def encode.huff.of source · line 247 · raw

@hh:0x83c5c81fb41f55ca634bdc7bde39a51b/src/jpeg.Huff -> Array<U32>

def encode.huff source · line 252 · raw

@+counts:List<&2, U32> -> @+syms:List<&2, U32> -> Array<U32>

def encode.book source · line 255 · raw

@+dcc:List<&2, U32> -> @+dcs:List<&2, U32> -> @+acc:List<&2, U32> -> @+acs:List<&2, U32> -> Book

def encode.cat.fr source · line 258 · raw

@done:Bool -> @+lt:Bool -> Bool

def encode.cat.on source · line 265 · raw

@fr:Bool -> U32

def encode.cat.c source · line 272 · raw

@fr:Bool -> @+cc:U32 -> U32

def encode.cat.lim source · line 279 · raw

@fr:Bool -> @+lim:U32 -> U32

def encode.cat.go source · line 286 · raw

@left:Nat -> @+done:U32 -> @+aa:U32 -> @+cc:U32 -> @+lim:U32 -> U32

def encode.cat source · line 294 · raw

@+vv:U32 -> U32

def encode.mag.s source · line 297 · raw

@+ss:U32 -> @+cat:U32 -> @+vv:U32 -> U32

def encode.mag source · line 304 · raw

@+cat:U32 -> @+vv:U32 -> U32

def encode.magp.z source · line 307 · raw

@zz:Bool -> @pp:Put -> @+cat:U32 -> @+vv:U32 -> Put

def encode.coded source · line 315 · raw

@got:Pair(Array<U32>, U32) -> Pair(Array<U32>, Code)

the indexed word is the length and the code

def encode.sym source · line 319 · raw

@aa:Array<U32> -> @+sym:U32 -> Pair(Array<U32>, Code)

def encode.dc.use source · line 322 · raw

@got:Pair(Array<U32>, Code) -> @pp:Put -> @+cat:U32 -> @+diff:U32 -> Pair(Array<U32>, Put)

def encode.dc source · line 327 · raw

@aa:Array<U32> -> @+pp:Put -> @+diff:U32 -> Pair(Array<U32>, Put)

def encode.clip.hi source · line 331 · raw

@hi:Bool -> @+vv:U32 -> @+lim:U32 -> U32

def encode.clip.lo source · line 338 · raw

@lo:Bool -> @+vv:U32 -> @+lim:U32 -> U32

def encode.clip.s source · line 345 · raw

@+ss:U32 -> @+vv:U32 -> @+lim:U32 -> U32

def encode.clip source · line 352 · raw

@+vv:U32 -> @+lim:U32 -> U32

def encode.emit source · line 355 · raw

@got:Pair(Array<U32>, Code) -> @pp:Put -> Pair(Array<U32>, Put)

def encode.eob source · line 360 · raw

@need:Bool -> @aa:Array<U32> -> @pp:Put -> Pair(Array<U32>, Put)

def encode.eob.on source · line 367 · raw

@need:Bool -> @st:Pair(Array<U32>, Put) -> Pair(Array<U32>, Put)

def encode.zrls.one source · line 372 · raw

@st:Pair(Array<U32>, Put) -> Pair(Array<U32>, Put)

def encode.zrls source · line 377 · raw

@left:Nat -> @st:Pair(Array<U32>, Put) -> Pair(Array<U32>, Put)

def encode.ac.mag source · line 384 · raw

@got:Pair(Array<U32>, Put) -> @+cat:U32 -> @+clip:U32 -> Pair(Array<U32>, Put)

def encode.ac.hit source · line 389 · raw

@got:Pair(Array<U32>, Put) -> @+sym:U32 -> @+cat:U32 -> @+clip:U32 -> Pair(Array<U32>, Put)

def encode.ac.step source · line 394 · raw

@+cc:U32 -> @+run:U32 -> @st:Pair(Array<U32>, Put) -> Pair(Array<U32>, Put)

def encode.ac source · line 402 · raw

@zz:List<&2, U32> -> @+run:U32 -> @st:Pair(Array<U32>, Put) -> Pair(Array<U32>, Put)

def encode.qnz source · line 411 · raw

@+qq:U32 -> U32

def encode.qdiv.s source · line 418 · raw

@+ss:U32 -> @+vv:U32 -> @+qq:U32 -> U32

def encode.qdiv source · line 425 · raw

@+vv:U32 -> @+qq:U32 -> U32

def encode.block.join source · line 428 · raw

@got:Pair(Array<U32>, Put) -> @dc2:Array<U32> -> @+dd:U32 -> Pair(Book, Pair(U32, Put))

def encode.block.dc source · line 432 · raw

@got:Pair(Array<U32>, Put) -> @ac:Array<U32> -> @+dd:U32 -> @rest:List<&2, U32> -> Pair(Book, Pair(U32, Put))

def encode.block.ac source · line 437 · raw

@book:Book -> @pp:Put -> @+pred:U32 -> @+dc0:U32 -> @rest:List<&2, U32> -> Pair(Book, Pair(U32, Put))

the clipped DC is written and kept, so the next block can predict from it

def encode.block.go source · line 443 · raw

@book:Book -> @pp:Put -> @+pred:U32 -> @zz:List<&2, U32> -> Pair(Book, Pair(U32, Put))

def encode.add64.acc source · line 450 · raw

@+ph:U32 -> @+pl:U32 -> @acc:Pair(U32, U32) -> Pair(U32, U32)

def encode.add64 source · line 457 · raw

@prod:Pair(U32, U32) -> @acc:Pair(U32, U32) -> Pair(U32, U32)

add a signed product onto a 64-bit accumulator

def encode.mac source · line 463 · raw

@+coef:U32 -> @+samp:U32 -> @acc:Pair(U32, U32) -> Pair(U32, U32)

one more product on the accumulator

def encode.q17 source · line 467 · raw

@acc:Pair(U32, U32) -> U32

the same rounding the matrix product applies to a finished sum

def encode.scale source · line 472 · raw

@+coef:U32 -> @+samp:U32 -> U32

def encode.two source · line 475 · raw

@+c0:U32 -> @+x0:U32 -> @+c1:U32 -> @+x1:U32 -> U32

def encode.two.n source · line 478 · raw

@+c0:U32 -> @+x0:U32 -> @+c1:U32 -> @+x1:U32 -> U32

def encode.four source · line 481 · raw

@+c0:U32 -> @+s0:U32 -> @+c1:U32 -> @+s1:U32 -> @+c2:U32 -> @+s2:U32 -> @+c3:U32 -> @+s3:U32 -> U32

def encode.even source · line 485 · raw

@+s0:U32 -> @+s1:U32 -> @+s2:U32 -> @+s3:U32 -> @+s4:U32 -> @+s5:U32 -> @+s6:U32 -> @+s7:U32 -> @+k0:U32 -> @+k2:U32 -> @+k6:U32 -> Oct

even frequencies: symmetric samples share one weight

def encode.odd source · line 508 · raw

@+d0:U32 -> @+d1:U32 -> @+d2:U32 -> @+d3:U32 -> @+o0:U32 -> @+o1:U32 -> @+o2:U32 -> @+o3:U32 -> Oct

odd frequencies: antisymmetric samples share one weight

def encode.dct8.od source · line 515 · raw

@+f0:U32 -> @+f2:U32 -> @+f4:U32 -> @+f6:U32 -> @od:Oct -> Oct

def encode.dct8.at source · line 521 · raw

@ev:Oct -> @od:Oct -> Oct

def encode.dct8.k source · line 527 · raw

@+s0:U32 -> @+s1:U32 -> @+s2:U32 -> @+s3:U32 -> @+s4:U32 -> @+s5:U32 -> @+s6:U32 -> @+s7:U32 -> @kern:Kern -> Oct

def encode.dct8 source · line 544 · raw

@samp:Oct -> @kern:Kern -> Oct

one 8-point transform. Pairing is the matrix product, so the rounded value matches.

def encode.take source · line 549 · raw

@row:List<&2, U32> -> Oct

def encode.put8 source · line 557 · raw

@+f0:U32 -> @+f1:U32 -> @+f2:U32 -> @+f3:U32 -> @+f4:U32 -> @+f5:U32 -> @+f6:U32 -> @+f7:U32 -> @aa:Array<U32> -> @+at:U32 -> @+step:U32 -> Array<U32>

def encode.lay source · line 580 · raw

@oo:Oct -> @aa:Array<U32> -> @+at:U32 -> Array<U32>

def encode.scatter source · line 585 · raw

@oo:Oct -> @aa:Array<U32> -> @+at:U32 -> Array<U32>

def encode.oct.pack source · line 590 · raw

@+s0:U32 -> @+s1:U32 -> @+s2:U32 -> @+s3:U32 -> @+s4:U32 -> @+s5:U32 -> @+s6:U32 -> @+s7:U32 -> @aa:Array<U32> -> Pair(Array<U32>, Oct)

def encode.oct.g7 source · line 603 · raw

@got:Pair(Array<U32>, U32) -> @+s0:U32 -> @+s1:U32 -> @+s2:U32 -> @+s3:U32 -> @+s4:U32 -> @+s5:U32 -> @+s6:U32 -> Pair(Array<U32>, Oct)

def encode.oct.g6 source · line 616 · raw

@got:Pair(Array<U32>, U32) -> @+s0:U32 -> @+s1:U32 -> @+s2:U32 -> @+s3:U32 -> @+s4:U32 -> @+s5:U32 -> @+i7:U32 -> Pair(Array<U32>, Oct)

def encode.oct.g5 source · line 629 · raw

@got:Pair(Array<U32>, U32) -> @+s0:U32 -> @+s1:U32 -> @+s2:U32 -> @+s3:U32 -> @+s4:U32 -> @+i6:U32 -> @+i7:U32 -> Pair(Array<U32>, Oct)

def encode.oct.g4 source · line 642 · raw

@got:Pair(Array<U32>, U32) -> @+s0:U32 -> @+s1:U32 -> @+s2:U32 -> @+s3:U32 -> @+i5:U32 -> @+i6:U32 -> @+i7:U32 -> Pair(Array<U32>, Oct)

def encode.oct.g3 source · line 655 · raw

@got:Pair(Array<U32>, U32) -> @+s0:U32 -> @+s1:U32 -> @+s2:U32 -> @+i4:U32 -> @+i5:U32 -> @+i6:U32 -> @+i7:U32 -> Pair(Array<U32>, Oct)

def encode.oct.g2 source · line 668 · raw

@got:Pair(Array<U32>, U32) -> @+s0:U32 -> @+s1:U32 -> @+i3:U32 -> @+i4:U32 -> @+i5:U32 -> @+i6:U32 -> @+i7:U32 -> Pair(Array<U32>, Oct)

def encode.oct.g1 source · line 681 · raw

@got:Pair(Array<U32>, U32) -> @+s0:U32 -> @+i2:U32 -> @+i3:U32 -> @+i4:U32 -> @+i5:U32 -> @+i6:U32 -> @+i7:U32 -> Pair(Array<U32>, Oct)

def encode.oct.g0 source · line 694 · raw

@got:Pair(Array<U32>, U32) -> @+i1:U32 -> @+i2:U32 -> @+i3:U32 -> @+i4:U32 -> @+i5:U32 -> @+i6:U32 -> @+i7:U32 -> Pair(Array<U32>, Oct)

def encode.oct.stride source · line 708 · raw

@aa:Array<U32> -> @+at:U32 -> @+step:U32 -> Pair(Array<U32>, Oct)

eight samples starting at at, every step slots

def encode.col.use source · line 718 · raw

@got:Pair(Array<U32>, Oct) -> @kern:Kern -> Pair(Array<U32>, Oct)

def encode.col source · line 724 · raw

@arr:Array<U32> -> @+at:U32 -> @kern:Kern -> Pair(Array<U32>, Oct)

one frequency column, read straight from the plane

def encode.pass1 source · line 727 · raw

@rows:List<&2, List<&2, U32>> -> @+kern:Kern -> @arr:Array<U32> -> @+at:U32 -> Array<U32>

def encode.pix.sink source · line 735 · raw

@aa:Array<U32> -> U32

def encode.book.sink source · line 742 · raw

@book:Book -> U32

def encode.pass2.done source · line 747 · raw

@st:Planes -> @kern:Kern -> Array<U32>

def encode.pass2.put source · line 755 · raw

@got:Pair(Array<U32>, Oct) -> @dst:Array<U32> -> @+at:U32 -> Planes

def encode.pass2.step source · line 760 · raw

@st:Planes -> @kern:Kern -> Planes

def encode.pass2 source · line 765 · raw

@left:Nat -> @st:Planes -> @+kern:Kern -> Array<U32>

def encode.pass.rows.done source · line 772 · raw

@st:Planes -> @kern:Kern -> Array<U32>

def encode.pass.rows.lay source · line 780 · raw

@got:Pair(Array<U32>, Oct) -> @+kern:Kern -> @dst:Array<U32> -> @+at:U32 -> Planes

def encode.pass.rows.next source · line 785 · raw

@st:Planes -> @+kern:Kern -> Planes

def encode.pass.rows source · line 791 · raw

@left:Nat -> @st:Planes -> @+kern:Kern -> Array<U32>

eight row transforms. left rows are still unread.

def encode.pass.mid source · line 798 · raw

@src:Array<U32> -> @+kern:Kern -> Array<U32>

def encode.freq source · line 802 · raw

@src:Array<U32> -> @+kern:Kern -> Array<U32>

level plane in, natural-order frequencies out

def encode.drain.pack source · line 805 · raw

@got:Pair(Array<U32>, U32) -> @acc:List<&2, U32> -> Pair(Array<U32>, Pair(U32, List<&2, U32>))

def encode.drain.step source · line 810 · raw

@st:Pair(Array<U32>, Pair(U32, List<&2, U32>)) -> @+idx:Nat -> Pair(Array<U32>, Pair(U32, List<&2, U32>))

def encode.drain.done source · line 814 · raw

@st:Pair(Array<U32>, Pair(U32, List<&2, U32>)) -> List<&2, U32>

def encode.drain source · line 820 · raw

@left:Nat -> @st:Pair(Array<U32>, Pair(U32, List<&2, U32>)) -> List<&2, U32>

read index 63 first, so the cons list comes out in order

def encode.drain.st source · line 827 · raw

@got:Pair(Array<U32>, U32) -> Pair(Array<U32>, Pair(U32, List<&2, U32>))

def encode.fdct.go source · line 832 · raw

@src:Array<U32> -> @kern:Kern -> List<&2, U32>

def encode.fdct source · line 835 · raw

@rows:List<&2, List<&2, U32>> -> @+cs:List<&2, U32> -> List<&2, U32>

def encode.level source · line 839 · raw

@xs:List<&2, U32> -> List<&2, U32>

def encode.levels source · line 846 · raw

@rows:List<&2, List<&2, U32>> -> List<&2, List<&2, U32>>

def encode.sat source · line 853 · raw

@over:Bool -> @+xx:U32 -> @+lim:U32 -> U32

def encode.sat8 source · line 860 · raw

@over:Bool -> @+vv:U32 -> U32

def encode.y source · line 867 · raw

@+rr:U32 -> @+gg:U32 -> @+bb:U32 -> U32

def encode.cb source · line 870 · raw

@+rr:U32 -> @+gg:U32 -> @+bb:U32 -> U32

def encode.cr source · line 873 · raw

@+rr:U32 -> @+gg:U32 -> @+bb:U32 -> U32

def encode.ych source · line 876 · raw

@+rr:U32 -> @+gg:U32 -> @+bb:U32 -> U32

def encode.cbch source · line 880 · raw

@+rr:U32 -> @+gg:U32 -> @+bb:U32 -> U32

def encode.crch source · line 884 · raw

@+rr:U32 -> @+gg:U32 -> @+bb:U32 -> U32

def encode.chan.w source · line 888 · raw

@+ch:U32 -> @+rr:U32 -> @+gg:U32 -> @+bb:U32 -> U32

def encode.chan source · line 897 · raw

@+pix:U32 -> @+ch:U32 -> U32

def encode.pix.load source · line 901 · raw

@left:Nat -> @px:List<&2, U32> -> @aa:Array<U32> -> @+ii:U32 -> Array<U32>

the first left samples, then the rest of the list is unused

def encode.sample.use source · line 911 · raw

@got:Pair(Array<U32>, U32) -> @+ch:U32 -> Pair(Array<U32>, U32)

def encode.sample source · line 916 · raw

@aa:Array<U32> -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> @+ch:U32 -> Pair(Array<U32>, U32)

one index into the sample array, instead of a walk from the head of the list

def encode.flat.both source · line 921 · raw

@aa:Bool -> @bb:Bool -> Bool

both samples are the neutral level

def encode.rowpix.step source · line 930 · raw

@+ss:U32 -> @got:Pair(Array<U32>, Pair(List<&2, U32>, Bool)) -> Pair(Array<U32>, Pair(List<&2, U32>, Bool))

def encode.rowpix.one source · line 934 · raw

@+ss:U32 -> @aa:Array<U32> -> Pair(Array<U32>, Pair(List<&2, U32>, Bool))

def encode.rowpix source · line 938 · raw

@left:Nat -> @got:Pair(Array<U32>, U32) -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> @+ch:U32 -> Pair(Array<U32>, Pair(List<&2, U32>, Bool))

got is the sample at x. left counts it and the samples after it.

def encode.rows.join source · line 959 · raw

@+row:List<&2, U32> -> @rf:Bool -> @rest:Pair(Array<U32>, Pair(List<&2, List<&2, U32>>, Bool)) -> Pair(Array<U32>, Pair(List<&2, List<&2, U32>>, Bool))

def encode.rows.one source · line 967 · raw

@+row:List<&2, U32> -> @rf:Bool -> @aa:Array<U32> -> Pair(Array<U32>, Pair(List<&2, List<&2, U32>>, Bool))

def encode.rows source · line 971 · raw

@left:Nat -> @got:Pair(Array<U32>, Pair(List<&2, U32>, Bool)) -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> @+ch:U32 -> Pair(Array<U32>, Pair(List<&2, List<&2, U32>>, Bool))

got is the row at y. left counts it and the rows after it.

def encode.droprows source · line 992 · raw

@rows:List<&2, List<&2, U32>> -> U32

def encode.zzq.take source · line 1001 · raw

@qs:List<&2, U32> -> Pair(U32, List<&2, U32>)

the next quant step, or 0 when the table has run out (qdiv turns 0 into 1)

def encode.zzq.go source · line 1009 · raw

@rest:List<&2, U32> -> @got:Pair(Array<U32>, U32) -> @qv:Pair(U32, List<&2, U32>) -> @acc:List<&2, U32> -> List<&2, U32>

got is the coefficient at the zigzag index just read. rest is the indexes after it.

def encode.zzq.enter source · line 1031 · raw

@zig:List<&2, U32> -> @arr:Array<U32> -> @qs:List<&2, U32> -> @acc:List<&2, U32> -> List<&2, U32>

def encode.zzq.load source · line 1040 · raw

@nat:List<&2, U32> -> @arr:Array<U32> -> @+at:U32 -> Array<U32>

def encode.zzq source · line 1048 · raw

@zig:List<&2, U32> -> @+nat:List<&2, U32> -> @+qs:List<&2, U32> -> @acc:List<&2, U32> -> List<&2, U32>

the coefficient block is an array, so each zigzag step is an index

def encode.zz source · line 1052 · raw

@flat:Bool -> @rows:List<&2, List<&2, U32>> -> @+kern:Kern -> @+zig:List<&2, U32> -> @+qs:List<&2, U32> -> List<&2, U32>

128 level-shifts to 0, and the integer DCT of that block is 0, so quant by 1 stays 0

def encode.block.pair source · line 1069 · raw

@got:Pair(Book, Pair(U32, Put)) -> @aa:Array<U32> -> Pair(Array<U32>, Pair(Book, Pair(U32, Put)))

def encode.block.use source · line 1074 · raw

@book:Book -> @pp:Put -> @+pred:U32 -> @got:Pair(Array<U32>, Pair(List<&2, List<&2, U32>>, Bool)) -> @+kern:Kern -> @+zig:List<&2, U32> -> @+qs:List<&2, U32> -> Pair(Array<U32>, Pair(Book, Pair(U32, Put)))

def encode.block source · line 1086 · raw

@book:Book -> @pp:Put -> @+pred:U32 -> @aa:Array<U32> -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> @+ch:U32 -> @ctx:Ctx -> Pair(Array<U32>, Pair(Book, Pair(U32, Put)))

def encode.nx source · line 1105 · raw

@more:Bool -> @+mx:U32 -> U32

def encode.ny source · line 1112 · raw

@more:Bool -> @+my:U32 -> U32

def encode.step.end source · line 1119 · raw

@got:Pair(Array<U32>, Pair(Book, Pair(U32, Put))) -> @+ydc:U32 -> @+bdc:U32 -> Pair(Array<U32>, Pair(Book, Pair(U32, Pair(U32, Pair(U32, Put)))))

def encode.scan.hit source · line 1127 · raw

@got:Pair(Array<U32>, Put) -> @arr:Array<U32> -> Scan

def encode.scan.skip source · line 1131 · raw

@sc:Scan -> @+cc:U32 -> Scan

def encode.scan.keep source · line 1137 · raw

@sc:Scan -> @+cc:U32 -> Scan

def encode.scan.bump source · line 1142 · raw

@zz:Bool -> @sc:Scan -> @+cc:U32 -> Scan

def encode.scan.val source · line 1150 · raw

@got:Pair(Array<U32>, U32) -> @+run:U32 -> @st:Pair(Array<U32>, Put) -> Scan

step is 1, so the frequency is the coefficient

def encode.scan.step source · line 1155 · raw

@sc:Scan -> @+gg:U32 -> Scan

def encode.scan.end source · line 1160 · raw

@sc:Scan -> Pair(Array<U32>, Put)

def encode.scan.ac source · line 1167 · raw

@rest:List<&2, U32> -> @sc:Scan -> Pair(Array<U32>, Put)

the rest of the zigzag, indexed in the frequency plane

def encode.scan.book source · line 1174 · raw

@got:Pair(Array<U32>, Put) -> @dc:Array<U32> -> @+dd:U32 -> Pair(Book, Pair(U32, Put))

def encode.scan.join source · line 1178 · raw

@got:Pair(Array<U32>, Put) -> @ac:Array<U32> -> @+dd:U32 -> @rest:List<&2, U32> -> @arr:Array<U32> -> Pair(Book, Pair(U32, Put))

def encode.scan.dc source · line 1188 · raw

@book:Book -> @pp:Put -> @+pred:U32 -> @+d0:U32 -> @rest:List<&2, U32> -> @arr:Array<U32> -> Pair(Book, Pair(U32, Put))

def encode.scan.open source · line 1201 · raw

@rest:List<&2, U32> -> @got:Pair(Array<U32>, U32) -> @book:Book -> @pp:Put -> @+pred:U32 -> Pair(Book, Pair(U32, Put))

def encode.scan.none source · line 1211 · raw

@book:Book -> @pp:Put -> @arr:Array<U32> -> @+pred:U32 -> Pair(Book, Pair(U32, Put))

def encode.scan source · line 1217 · raw

@book:Book -> @pp:Put -> @+pred:U32 -> @arr:Array<U32> -> @zig:List<&2, U32> -> Pair(Book, Pair(U32, Put))

DC at the first zigzag index, then the AC run, both read from the frequency plane

def encode.chan.flat source · line 1224 · raw

@plane:Array<U32> -> @book:Book -> @pp:Put -> @+pred:U32 -> @+kern:Kern -> @+zig:List<&2, U32> -> @+qs:List<&2, U32> -> Pair(Book, Pair(U32, Put))

def encode.chan.mix source · line 1239 · raw

@plane:Array<U32> -> @book:Book -> @pp:Put -> @+pred:U32 -> @+kern:Kern -> @zig:List<&2, U32> -> @qs:List<&2, U32> -> Pair(Book, Pair(U32, Put))

def encode.chan.go source · line 1251 · raw

@flat:Bool -> @plane:Array<U32> -> @book:Book -> @pp:Put -> @+pred:U32 -> @+kern:Kern -> @+zig:List<&2, U32> -> @+qs:List<&2, U32> -> Pair(Book, Pair(U32, Put))

def encode.pix.at source · line 1267 · raw

@aa:Array<U32> -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> Pair(Array<U32>, U32)

def encode.tile.store source · line 1270 · raw

@got:Pair(Array<U32>, U32) -> @ys:Array<U32> -> @bs:Array<U32> -> @rs:Array<U32> -> @fy:Bool -> @fb:Bool -> @fr:Bool -> @+ii:U32 -> Tile

def encode.tile.pix source · line 1291 · raw

@tt:Tile -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> @+ii:U32 -> Tile

def encode.tile.row source · line 1296 · raw

@left:Nat -> @tt:Tile -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> @+ii:U32 -> Tile

def encode.tile.rows source · line 1304 · raw

@left:Nat -> @tt:Tile -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> @+ii:U32 -> Tile

def encode.tile source · line 1313 · raw

@aa:Array<U32> -> @+ww:U32 -> @+hh:U32 -> @+xx:U32 -> @+yy:U32 -> Tile

three level planes from one walk of this MCU

def encode.chan.pair source · line 1317 · raw

@got:Pair(Book, Pair(U32, Put)) -> @aa:Array<U32> -> Pair(Array<U32>, Pair(Book, Pair(U32, Put)))

def encode.step.cr source · line 1322 · raw

@got:Pair(Book, Pair(U32, Put)) -> @aa:Array<U32> -> @rs:Array<U32> -> @fr:Bool -> @+ydc:U32 -> @+pr:U32 -> @+kern:Kern -> @+zig:List<&2, U32> -> @+qs:List<&2, U32> -> Pair(Array<U32>, Pair(Book, Pair(U32, Pair(U32, Pair(U32, Put)))))

def encode.step.cb source · line 1336 · raw

@got:Pair(Book, Pair(U32, Put)) -> @aa:Array<U32> -> @bs:Array<U32> -> @rs:Array<U32> -> @fb:Bool -> @fr:Bool -> @+pb:U32 -> @+pr:U32 -> @+kern:Kern -> @+zig:List<&2, U32> -> @+qs:List<&2, U32> -> Pair(Array<U32>, Pair(Book, Pair(U32, Pair(U32, Pair(U32, Put)))))

def encode.step.tile source · line 1352 · raw

@tt:Tile -> @book:Book -> @bit:Put -> @+py:U32 -> @+pb:U32 -> @+pr:U32 -> @+kern:Kern -> @+zig:List<&2, U32> -> @+qs:List<&2, U32> -> Pair(Array<U32>, Pair(Book, Pair(U32, Pair(U32, Pair(U32, Put)))))

def encode.step.y source · line 1368 · raw

@aa:Array<U32> -> @book:Book -> @bit:Put -> @+py:U32 -> @+pb:U32 -> @+pr:U32 -> @+xx:U32 -> @+yy:U32 -> @+ww:U32 -> @+hh:U32 -> @+ctx:Ctx -> Pair(Array<U32>, Pair(Book, Pair(U32, Pair(U32, Pair(U32, Put)))))

one walk of the MCU, then Y, Cb, and Cr. Each clipped DC is the next predictor.

def encode.mcus.done source · line 1385 · raw

@got:Pair(Array<U32>, Pair(Book, Pair(U32, Pair(U32, Pair(U32, Put))))) -> Put

def encode.mcus source · line 1392 · raw

@left:Nat -> @got:Pair(Array<U32>, Pair(Book, Pair(U32, Pair(U32, Pair(U32, Put))))) -> @+mx:U32 -> @+my:U32 -> @+mw:U32 -> @+ww:U32 -> @+hh:U32 -> @+ctx:Ctx -> Put

def encode.finish source · line 1413 · raw

@+ww:U32 -> @+hh:U32 -> @ent:List<&2, U32> -> @+dcc:List<&2, U32> -> @+dcs:List<&2, U32> -> @+acc:List<&2, U32> -> @+acs:List<&2, U32> -> List<&2, U32>

def encode.hunt.nil source · line 1425 · raw

@+seen:U32 -> Pair(Bool, List<&2, U32>)

samples before a mismatch were packed 8421504, so that prefix can be replayed

def encode.hunt.mix source · line 1428 · raw

@+seen:U32 -> @+hh:U32 -> @tt:List<&2, U32> -> Pair(Bool, List<&2, U32>)

def encode.hunt.rest source · line 1431 · raw

@xs:List<&2, U32> -> Pair(Bool, List<&2, U32>)

def encode.hunt.done source · line 1436 · raw

@eq:Bool -> @+hh:U32 -> @xs:List<&2, U32> -> @+seen:U32 -> Pair(Bool, List<&2, U32>)

no samples remain after h

def encode.hunt.empty source · line 1444 · raw

@eq:Bool -> @+hh:U32 -> @+seen:U32 -> Pair(Bool, List<&2, U32>)

the list ended before the area did

def encode.hunt.go source · line 1452 · raw

@left:Nat -> @xs:List<&2, U32> -> @eq:Bool -> @+hh:U32 -> @+seen:U32 -> Pair(Bool, List<&2, U32>)

h was just read. left samples remain after it. seen neutral samples precede it.

def encode.hold.no source · line 1468 · raw

@+seen:U32 -> @+cc:U32 -> @tail:List<&2, U32> -> Pair(Bool, List<&2, U32>)

the area was one colour. seen of those samples are replayed only on a miss.

def encode.hold.yes source · line 1471 · raw

@xs:List<&2, U32> -> @+cc:U32 -> @+hh:U32 -> @+seen:U32 -> Pair(Bool, List<&2, U32>)

def encode.hold.done source · line 1476 · raw

@eq:Bool -> @+hh:U32 -> @xs:List<&2, U32> -> @+cc:U32 -> @+seen:U32 -> Pair(Bool, List<&2, U32>)

def encode.hold.empty source · line 1483 · raw

@eq:Bool -> @+hh:U32 -> @+cc:U32 -> @+seen:U32 -> Pair(Bool, List<&2, U32>)

def encode.hold.go source · line 1492 · raw

@left:Nat -> @xs:List<&2, U32> -> @eq:Bool -> @+hh:U32 -> @+cc:U32 -> @+seen:U32 -> Pair(Bool, List<&2, U32>)

h was just read. left samples remain after it. seen copies of c precede it.

def encode.watch.neu source · line 1508 · raw

@got:Pair(Bool, List<&2, U32>) -> Pair(U32, Pair(U32, List<&2, U32>))

0 neutral, 1 one other colour, 2 mixed. A short list stays mixed: the plane's gaps are 0.

def encode.watch.sol source · line 1517 · raw

@got:Pair(Bool, List<&2, U32>) -> @+hh:U32 -> Pair(U32, Pair(U32, List<&2, U32>))

def encode.watch.pick source · line 1527 · raw

@neu:Bool -> @kk:Nat -> @tt:List<&2, U32> -> @+hh:U32 -> Pair(U32, Pair(U32, List<&2, U32>))

def encode.watch source · line 1534 · raw

@left:Nat -> @xs:List<&2, U32> -> Pair(U32, Pair(U32, List<&2, U32>))

def encode.pack.byte source · line 1547 · raw

@+buf:U32 -> @+len:U32 -> @+code:U32 -> U32

low len bits of code join the open byte; a finished byte is stuffed

def encode.pack.full source · line 1550 · raw

@full:Bool -> @out:List<&2, U32> -> @+buf:U32 -> @+nn:U32 -> @+len:U32 -> @+code:U32 -> Put

def encode.pack.keep source · line 1557 · raw

@pp:Put -> @+lo:U32 -> @+rest:U32 -> Put

def encode.pack.span source · line 1562 · raw

@out:List<&2, U32> -> @+buf:U32 -> @+nn:U32 -> @+len:U32 -> @+code:U32 -> Put

def encode.pack.fit source · line 1568 · raw

@fit:Bool -> @out:List<&2, U32> -> @+buf:U32 -> @+nn:U32 -> @+len:U32 -> @+code:U32 -> Put

def encode.pack source · line 1575 · raw

@pp:Put -> @+len:U32 -> @+code:U32 -> Put

def encode.zput source · line 1581 · raw

@pp:Put -> Put

Annex K luminance: a zero block is DC 00 then EOB 1010

def encode.ztri source · line 1584 · raw

@pp:Put -> Put

def encode.neutral.mcus source · line 1587 · raw

@left:Nat -> @pp:Put -> Put

def encode.neutral source · line 1595 · raw

@+ww:U32 -> @+hh:U32 -> List<&2, U32>

the entropy-coded bytes of a neutral picture: every MCU is three zero blocks

def encode.solid.end source · line 1601 · raw

@got:Pair(Array<U32>, Pair(Book, Pair(U32, Put))) -> Put

the rest of a solid picture is the same DC, so each later block is a zero difference

def encode.solid.cr source · line 1608 · raw

@got:Pair(Array<U32>, Pair(Book, Pair(U32, Put))) -> @+ctx:Ctx -> Put

def encode.solid.cb source · line 1613 · raw

@got:Pair(Array<U32>, Pair(Book, Pair(U32, Put))) -> @+ctx:Ctx -> Put

def encode.solid.y source · line 1618 · raw

@aa:Array<U32> -> @book:Book -> @bit:Put -> @+ctx:Ctx -> Put

def encode.solid source · line 1623 · raw

@+ww:U32 -> @+hh:U32 -> @+color:U32 -> List<&2, U32>

one colour repeated. The first MCU is that block; every later MCU is three zero differences. The result is the entropy-coded bytes.

def encode.go source · line 1633 · raw

@+ww:U32 -> @+hh:U32 -> @px:List<&2, U32> -> List<&2, U32>

the entropy-coded bytes of any other picture, MCU by MCU

def encode.dispatch source · line 1643 · raw

@+tag:U32 -> @+color:U32 -> @px:List<&2, U32> -> @+ww:U32 -> @+hh:U32 -> List<&2, U32>

the entropy-coded bytes, by what the watch found: neutral, one solid colour, or anything else

def encode.arm.use source · line 1657 · raw

@got:Pair(U32, Pair(U32, List<&2, U32>)) -> @+ww:U32 -> @+hh:U32 -> List<&2, U32>

the watch's answer, dispatched

def encode.arm source · line 1663 · raw

@+ww:U32 -> @+hh:U32 -> @px:List<&2, U32> -> List<&2, U32>

the entropy-coded bytes of an accepted size

def encode.pick source · line 1666 · raw

@bad:Bool -> @+ww:U32 -> @+hh:U32 -> @px:List<&2, U32> -> List<&2, U32>

def encode source · line 1676 · raw

@+ww:U32 -> @+hh:U32 -> @px:List<&2, U32> -> List<&2, U32>

baseline sequential 4:4:4 JPEG bytes for packed RGB samples, or SOI EOI when the size is rejected