summaryrefslogtreecommitdiff
path: root/appl/grid/readjpg.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/grid/readjpg.b')
-rw-r--r--appl/grid/readjpg.b1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/appl/grid/readjpg.b b/appl/grid/readjpg.b
new file mode 100644
index 00000000..9409c56a
--- /dev/null
+++ b/appl/grid/readjpg.b
@@ -0,0 +1,1146 @@
+implement Readjpg;
+
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+ draw: Draw;
+ Display, Image: import draw;
+include "grid/readjpg.m";
+
+display: ref Display;
+slowread: int;
+zeroints := array[64] of { * => 0 };
+
+init(disp: ref Draw->Display)
+{
+ sys = load Sys Sys->PATH;
+ draw = load Draw Draw->PATH;
+ display = disp;
+ init_tabs();
+}
+
+fjpg2img(fd: ref sys->FD, cachepath: string, chanin, chanout: chan of string): ref Image
+{
+ if (fd == nil) return nil;
+ sync := chan of int;
+ imgchan := chan of ref Image;
+ is := newImageSource(0,0);
+ spawn slowreads(is,fd,cachepath, sync, chanout);
+ srpid := <- sync;
+ if (srpid == -1) return nil;
+ spawn getjpegimg(is, chanout, imgchan, sync);
+ gjipid := <- sync;
+
+ for (;;) alt {
+ ctl := <- chanin =>
+ if (ctl == "kill") {
+ if (srpid != -1) kill(srpid);
+ kill(gjipid);
+ return nil;
+ }
+ img := <- imgchan =>
+ if (srpid != -1) kill(srpid);
+ return img;
+ err := <- sync =>
+ if (err == 0) srpid = -1;
+ else {
+ kill(gjipid);
+ return nil;
+ }
+ }
+}
+
+jpg2img(filename, cachepath: string, chanin, chanout: chan of string): ref Image
+{
+ fd := sys->open(filename, sys->OREAD);
+ return fjpg2img(fd, cachepath, chanin, chanout);
+}
+
+kill(pid: int)
+{
+ pctl := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE);
+ if (pctl != nil)
+ sys->write(pctl, array of byte "kill", len "kill");
+}
+
+filelength(fd : ref sys->FD): int
+{
+ (n, dir) := sys->fstat(fd);
+ if (n == -1) return -1;
+ filelen := int dir.length;
+ return filelen;
+}
+
+slowreads(is: ref ImageSource, fd : ref sys->FD, cachepath: string, sync: chan of int, chanout: chan of string)
+{
+ filelen := filelength(fd);
+ if (filelen < 1) {
+ sync <-= -1;
+ return;
+ }
+ is.data = array[filelen] of byte;
+ slowread = 0;
+
+ sync <-= sys->pctl(0, nil);
+
+ cachefd : ref sys->FD = nil;
+ if (cachepath != "") cachefd = sys->create(cachepath, sys->OWRITE, 8r666);
+ if (chanout != nil) {
+ chanout <-= "l2 Loading...";
+ chanout <-= "pc 0";
+ }
+ i : int;
+ for (;;) {
+ i = sys->read(fd,is.data[slowread:], 8192);
+ if (i < 1) break;
+ if (cachefd != nil)
+ sys->write(cachefd, is.data[slowread:],i);
+ slowread += i;
+ if (chanout != nil)
+ chanout <-= "pc "+string ((slowread*100)/filelen);
+ sys->sleep(0);
+ }
+ if (i == -1 || slowread == 0) {
+ sync <-= -1;
+ return;
+ }
+ newdata := array[slowread] of byte;
+ newdata = is.data[:slowread];
+ is.data = newdata;
+ if (cachepath != "" && slowread < filelen)
+ sys->remove(cachepath);
+ sync <-= 0;
+}
+
+wait4data(n: int)
+{
+ for(;;) {
+ if (slowread > n) break;
+ sys->sleep(100);
+ }
+}
+
+newImageSource(w, h: int) : ref ImageSource
+{
+ is := ref ImageSource(
+ w,h, # width, height
+ 0,0, # origw, origh
+ 0, # i
+ nil, # jhdr
+ nil # data
+ );
+ return is;
+}
+
+getjpeghdr(is: ref ImageSource)
+{
+ h := ref Jpegstate(
+ 0, 0, # sr, cnt
+ 0, # Nf
+ nil, # comp
+ byte 0, # mode,
+ 0, 0, # X, Y
+ nil, # qt
+ nil, nil, # dcht, acht
+ 0, # Ns
+ nil, # scomp
+ 0, 0, # Ss, Se
+ 0, 0, # Ah, Al
+ 0, 0, # ri, nseg
+ nil, # nblock
+ nil, nil, # dccoeff, accoeff
+ 0, 0, 0, 0 # nacross, ndown, Hmax, Vmax
+ );
+ is.jstate = h;
+ if(jpegmarker(is) != SOI)
+ sys->print("Error: Jpeg expected SOI marker\n");
+ (m, n) := jpegtabmisc(is);
+ if(!(m == SOF || m == SOF2))
+ sys->print("Error: Jpeg expected Frame marker");
+ nil = getc(is); # sample precision
+ h.Y = getbew(is);
+ h.X = getbew(is);
+ h.Nf = getc(is);
+ h.comp = array[h.Nf] of Framecomp;
+ h.nblock = array[h.Nf] of int;
+ for(i:=0; i<h.Nf; i++) {
+ h.comp[i].C = getc(is);
+ (H, V) := nibbles(getc(is));
+ h.comp[i].H = H;
+ h.comp[i].V = V;
+ h.comp[i].Tq = getc(is);
+ h.nblock[i] =H*V;
+ }
+ h.mode = byte m;
+ is.origw = h.X;
+ is.origh = h.Y;
+ setdims(is);
+ if(n != 6+3*h.Nf)
+ sys->print("Error: Jpeg bad SOF length");
+}
+
+setdims(is: ref ImageSource)
+{
+ sw := is.origw;
+ sh := is.origh;
+ dw := is.width;
+ dh := is.height;
+ if(dw == 0 && dh == 0) {
+ dw = sw;
+ dh = sh;
+ }
+ else if(dw == 0 || dh == 0) {
+ if(dw == 0) {
+ dw = int ((real sw) * (real dh/real sh));
+ if(dw == 0)
+ dw = 1;
+ }
+ else {
+ dh = int ((real sh) * (real dw/real sw));
+ if(dh == 0)
+ dh = 1;
+ }
+ }
+ is.width = dw;
+ is.height = dh;
+}
+
+jpegmarker(is: ref ImageSource) : int
+{
+ if(getc(is) != 16rFF)
+ sys->print("Error: Jpeg expected marker");
+ return getc(is);
+}
+
+getbew(is: ref ImageSource) : int
+{
+ c0 := getc(is);
+ c1 := getc(is);
+ return (c0<<8) + c1;
+}
+
+getn(is: ref ImageSource, n: int) : (array of byte, int)
+{
+ if (is.i + n > slowread - 1) wait4data(is.i + n);
+ a := is.data;
+ i := is.i;
+ if(i + n <= len a)
+ is.i += n;
+# else
+# sys->print("Error: premature eof");
+ return (a, i);
+}
+
+# Consume tables and miscellaneous marker segments,
+# returning the marker id and length of the first non-such-segment
+# (after having consumed the marker).
+# May raise "premature eof" or other exception.
+jpegtabmisc(is: ref ImageSource) : (int, int)
+{
+ h := is.jstate;
+ m, n : int;
+Loop:
+ for(;;) {
+ h.nseg++;
+ m = jpegmarker(is);
+ n = 0;
+ if(m != EOI)
+ n = getbew(is) - 2;
+ case m {
+ SOF or SOF2 or SOS or EOI =>
+ break Loop;
+
+ APPn+0 =>
+ if(h.nseg==1 && n >= 6) {
+ (buf, i) := getn(is, 6);
+ n -= 6;
+ if(string buf[i:i+4]=="JFIF") {
+ vers0 := int buf[i+5];
+ vers1 := int buf[i+6];
+ if(vers0>1 || vers1>2)
+ sys->print("Error: Jpeg unimplemented version");
+ }
+ }
+
+ APPn+1 to APPn+15 =>
+ ;
+
+ DQT =>
+ jpegquanttables(is, n);
+ n = 0;
+
+ DHT =>
+ jpeghuffmantables(is, n);
+ n = 0;
+
+ DRI =>
+ h.ri =getbew(is);
+ n -= 2;
+
+ COM =>
+ ;
+
+ * =>
+ sys->print("Error: Jpeg unexpected marker");
+ }
+ if(n > 0)
+ getn(is, n);
+ }
+ return (m, n);
+}
+
+# Consume huffman tables, raising exception on error.
+jpeghuffmantables(is: ref ImageSource, n: int)
+{
+ h := is.jstate;
+ if(h.dcht == nil) {
+ h.dcht = array[4] of ref Huffman;
+ h.acht = array[4] of ref Huffman;
+ }
+ for(l:= 0; l < n; )
+ l += jpeghuffmantable(is);
+ if(l != n)
+ sys->print("Error: Jpeg huffman table bad length");
+}
+
+jpeghuffmantable(is: ref ImageSource) : int
+{
+ t := ref Huffman;
+ h := is.jstate;
+ (Tc, th) := nibbles(getc(is));
+ if(Tc > 1)
+ sys->print("Error: Jpeg unknown Huffman table class");
+ if(th>3 || (h.mode==byte SOF && th>1))
+ sys->print("Error: Jpeg unknown Huffman table index");
+ if(Tc == 0)
+ h.dcht[th] = t;
+ else
+ h.acht[th] = t;
+
+ # flow chart C-2
+ (b, bi) := getn(is, 16);
+ numcodes := array[16] of int;
+ nsize := 0;
+ for(i:=0; i<16; i++)
+ nsize += (numcodes[i] = int b[bi+i]);
+ t.size = array[nsize+1] of int;
+ k := 0;
+ for(i=1; i<=16; i++) {
+ n :=numcodes[i-1];
+ for(j:=0; j<n; j++)
+ t.size[k++] = i;
+ }
+ t.size[k] = 0;
+
+ # initialize HUFFVAL
+ t.val = array[nsize] of int;
+ (b, bi) = getn(is, nsize);
+ for(i=0; i<nsize; i++)
+ t.val[i] = int b[bi++];
+
+ # flow chart C-3
+ t.code = array[nsize+1] of int;
+ k = 0;
+ code := 0;
+ si := t.size[0];
+ for(;;) {
+ do
+ t.code[k++] = code++;
+ while(t.size[k] == si);
+ if(t.size[k] == 0)
+ break;
+ do {
+ code <<= 1;
+ si++;
+ } while(t.size[k] != si);
+ }
+
+ # flow chart F-25
+ t.mincode = array[17] of int;
+ t.maxcode = array[17] of int;
+ t.valptr = array[17] of int;
+ i = 0;
+ j := 0;
+ F25:
+ for(;;) {
+ for(;;) {
+ i++;
+ if(i > 16)
+ break F25;
+ if(numcodes[i-1] != 0)
+ break;
+ t.maxcode[i] = -1;
+ }
+ t.valptr[i] = j;
+ t.mincode[i] = t.code[j];
+ j += int numcodes[i-1]-1;
+ t.maxcode[i] = t.code[j];
+ j++;
+ }
+
+ # create byte-indexed fast path tables
+ t.value = array[256] of int;
+ t.shift = array[256] of int;
+ maxcode := t.maxcode;
+ # stupid startup algorithm: just run machine for each byte value
+ Bytes:
+ for(v:=0; v<256; v++){
+ cnt := 7;
+ m := 1<<7;
+ code = 0;
+ sr := v;
+ i = 1;
+ for(;;i++){
+ if(sr & m)
+ code |= 1;
+ if(code <= maxcode[i])
+ break;
+ code <<= 1;
+ m >>= 1;
+ if(m == 0){
+ t.shift[v] = 0;
+ t.value[v] = -1;
+ continue Bytes;
+ }
+ cnt--;
+ }
+ t.shift[v] = 8-cnt;
+ t.value[v] = t.val[t.valptr[i]+(code-t.mincode[i])];
+ }
+
+ return nsize+17;
+}
+
+jpegquanttables(is: ref ImageSource, n: int)
+{
+ h := is.jstate;
+ if(h.qt == nil)
+ h.qt = array[4] of array of int;
+ for(l:=0; l<n; )
+ l += jpegquanttable(is);
+ if(l != n)
+ sys->print("Error: Jpeg quant table bad length");
+}
+
+jpegquanttable(is: ref ImageSource): int
+{
+ (pq, tq) := nibbles(getc(is));
+ if(pq > 1)
+ sys->print("Error: Jpeg unknown quantization table class");
+ if(tq > 3)
+ sys->print("Error: Jpeg bad quantization table index");
+ q := array[64] of int;
+ is.jstate.qt[tq] = q;
+ for(i:=0; i<64; i++) {
+ if(pq == 0)
+ q[i] =getc(is);
+ else
+ q[i] = getbew(is);
+ }
+ return 1+(64*(1+pq));;
+}
+
+# Have just read Frame header.
+# Now expect:
+# ((tabl/misc segment(s))* (scan header) (entropy coded segment)+)+ EOI
+getjpegimg(is:ref ImageSource,chanout:chan of string,imgchan: chan of ref Image,sync: chan of int)
+{
+ sync <-= sys->pctl(0, nil);
+ getjpeghdr(is);
+ h := is.jstate;
+ chans: array of array of byte = nil;
+ for(;;) {
+ (m, n) := jpegtabmisc(is);
+ if(m == EOI)
+ break;
+ if(m != SOS)
+ sys->print("Error: Jpeg expected start of scan");
+
+ h.Ns = getc(is);
+ scomp := array[h.Ns] of Scancomp;
+ for(i := 0; i < h.Ns; i++) {
+ scomp[i].C = getc(is);
+ (scomp[i].tdc, scomp[i].tac) = nibbles(getc(is));
+ }
+ h.scomp = scomp;
+ h.Ss = getc(is);
+ h.Se = getc(is);
+ (h.Ah, h.Al) = nibbles(getc(is));
+ if(n != 4+h.Ns*2)
+ sys->print("Error: Jpeg SOS header wrong length");
+
+ if(h.mode == byte SOF) {
+ if(chans != nil)
+ sys->print("Error: Jpeg baseline has > 1 scan");
+ chans = jpegbaselinescan(is, chanout);
+ }
+ }
+ if(chans == nil)
+ sys->print("Error: jpeg has no image");
+ width := is.width;
+ height := is.height;
+ if(width != h.X || height != h.Y) {
+ for(k := 0; k < len chans; k++)
+ chans[k] = resample(chans[k], h.X, h.Y, width, height);
+ }
+
+ r := remapYCbCr(chans, chanout);
+ im := newimage24(width, height);
+ im.writepixels(im.r, r);
+ imgchan <-= im;
+}
+
+newimage24(w, h: int) : ref Image
+{
+ im := display.newimage(((0,0),(w,h)), Draw->RGB24, 0, Draw->White);
+ if(im == nil)
+ sys->print("Error: out of memory");
+ return im;
+}
+
+remapYCbCr(chans: array of array of byte, chanout: chan of string): array of byte
+{
+ Y := chans[0];
+ Cb := chans[1];
+ Cr := chans[2];
+
+ rgb := array [3*len Y] of byte;
+ bix := 0;
+ lY := len Y;
+ n := lY / 20;
+ count := 0;
+ for (i := 0; i < lY; i++) {
+ if ((count == 0 || count >= n ) && chanout != nil) {
+ chanout <-= "l2 Processing...";
+ chanout <-= "pc "+string ((100*i)/ lY);
+ count = 0;
+ }
+ count++;
+ y := int Y[i];
+ cb := int Cb[i];
+ cr := int Cr[i];
+ r := y + Cr2r[cr];
+ g := y - Cr2g[cr] - Cb2g[cb];
+ b := y + Cb2b[cb];
+
+ rgb[bix++] = clampb[b+CLAMPBOFF];
+ rgb[bix++] = clampb[g+CLAMPBOFF];
+ rgb[bix++] = clampb[r+CLAMPBOFF];
+ }
+ if (chanout != nil) chanout <-= "pc 100";
+ return rgb;
+}
+
+zig := array[64] of {
+ 0, 1, 8, 16, 9, 2, 3, 10, 17, # 0-7
+ 24, 32, 25, 18, 11, 4, 5, # 8-15
+ 12, 19, 26, 33, 40, 48, 41, 34, # 16-23
+ 27, 20, 13, 6, 7, 14, 21, 28, # 24-31
+ 35, 42, 49, 56, 57, 50, 43, 36, # 32-39
+ 29, 22, 15, 23, 30, 37, 44, 51, # 40-47
+ 58, 59, 52, 45, 38, 31, 39, 46, # 48-55
+ 53, 60, 61, 54, 47, 55, 62, 63 # 56-63
+};
+
+jpegbaselinescan(is: ref ImageSource,chanout: chan of string) : array of array of byte
+{
+ h := is.jstate;
+ Ns := h.Ns;
+ if(Ns != h.Nf)
+ sys->print("Error: Jpeg baseline needs Ns==Nf");
+ if(!(Ns==3 || Ns==1))
+ sys->print("Error: Jpeg baseline needs Ns==1 or 3");
+
+
+ chans := array[h.Nf] of array of byte;
+ for(k:=0; k<h.Nf; k++)
+ chans[k] = array[h.X*h.Y] of byte;
+
+ # build per-component arrays
+ Td := array[Ns] of int;
+ Ta := array[Ns] of int;
+ data := array[Ns] of array of array of int;
+ H := array[Ns] of int;
+ V := array[Ns] of int;
+ DC := array[Ns] of int;
+
+ # compute maximum H and V
+ Hmax := 0;
+ Vmax := 0;
+ for(comp:=0; comp<Ns; comp++) {
+ if(h.comp[comp].H > Hmax)
+ Hmax = h.comp[comp].H;
+ if(h.comp[comp].V > Vmax)
+ Vmax = h.comp[comp].V;
+ }
+ # initialize data structures
+ allHV1 := 1;
+ for(comp=0; comp<Ns; comp++) {
+ # JPEG requires scan components to be in same order as in frame,
+ # so if both have 3 we know scan is Y Cb Cr and there's no need to
+ # reorder
+ Td[comp] = h.scomp[comp].tdc;
+ Ta[comp] = h.scomp[comp].tac;
+ H[comp] = h.comp[comp].H;
+ V[comp] = h.comp[comp].V;
+ nblock := H[comp]*V[comp];
+ if(nblock != 1)
+ allHV1 = 0;
+
+ # data[comp]: needs (3+nblock)*4 + nblock*(3+8*8)*4 bytes
+
+ data[comp] = array[nblock] of array of int;
+ DC[comp] = 0;
+ for(m:=0; m<nblock; m++)
+ data[comp][m] = array[8*8] of int;
+ }
+
+ ri := h.ri;
+
+ h.cnt = 0;
+ h.sr = 0;
+ nacross := ((h.X+(8*Hmax-1))/(8*Hmax));
+ nmcu := ((h.Y+(8*Vmax-1))/(8*Vmax))*nacross;
+ n1 := 0;
+ n2 := nmcu / 20;
+ for(mcu:=0; mcu<nmcu; ) {
+ if ((n1 == 0 || n1 >= n2) && chanout != nil && slowread == len is.data) {
+ chanout <-= "l2 Scanning... ";
+ chanout <-= "pc "+string ((100*mcu)/nmcu);
+ n1 = 0;
+ }
+ n1 ++;
+ for(comp=0; comp<Ns; comp++) {
+ dcht := h.dcht[Td[comp]];
+ acht := h.acht[Ta[comp]];
+ qt := h.qt[h.comp[comp].Tq];
+
+ for(block:=0; block<H[comp]*V[comp]; block++) {
+ # F-22
+ t := jdecode(is, dcht);
+ diff := jreceive(is, t);
+ DC[comp] += diff;
+
+ # F-23
+ zz := data[comp][block];
+ zz[0:] = zeroints;
+ zz[0] = qt[0]*DC[comp];
+ k = 1;
+
+ for(;;) {
+ rs := jdecode(is, acht);
+ (rrrr, ssss) := nibbles(rs);
+ if(ssss == 0){
+ if(rrrr != 15)
+ break;
+ k += 16;
+ }else{
+ k += rrrr;
+ z := jreceive(is, ssss);
+ zz[zig[k]] = z*qt[k];
+ if(k == 63)
+ break;
+ k++;
+ }
+ }
+
+ idct(zz);
+ }
+ }
+
+ # rotate colors to RGB and assign to bytes
+ colormap(h, chans, data[0], data[1], data[2], mcu, nacross, Hmax, Vmax, H, V);
+
+ # process restart marker, if present
+ mcu++;
+ if(ri>0 && mcu<nmcu && mcu%ri==0){
+ jrestart(is, mcu);
+ for(comp=0; comp<Ns; comp++)
+ DC[comp] = 0;
+ }
+ }
+ if (chanout != nil) chanout <-= "pc 100";
+ return chans;
+}
+
+jrestart(is: ref ImageSource, mcu: int)
+{
+ h := is.jstate;
+ ri := h.ri;
+ restart := mcu/ri-1;
+ rst, nskip: int;
+ nskip = 0;
+ do {
+ do{
+ rst = jnextborm(is);
+ nskip++;
+ }while(rst>=0 && rst!=16rFF);
+ if(rst == 16rFF){
+ rst = jnextborm(is);
+ nskip++;
+ }
+ } while(rst>=0 && (rst&~7)!= RST);
+ if(nskip != 2 || rst < 0 || ((rst&7) != (restart&7)))
+ sys->print("Error: Jpeg restart problem");
+ h.cnt = 0;
+ h.sr = 0;
+}
+
+jc1: con 2871; # 1.402 * 2048
+jc2: con 705; # 0.34414 * 2048
+jc3: con 1463; # 0.71414 * 2048
+jc4: con 3629; # 1.772 * 2048
+
+CLAMPBOFF: con 300;
+NCLAMPB: con CLAMPBOFF+256+CLAMPBOFF;
+CLAMPNOFF: con 64;
+NCLAMPN: con CLAMPNOFF+256+CLAMPNOFF;
+
+clampb: array of byte; # clamps byte values
+
+init_tabs()
+{
+ j: int;
+ clampb = array[NCLAMPB] of byte;
+ for(j=0; j<CLAMPBOFF; j++)
+ clampb[j] = byte 0;
+ for(j=0; j<256; j++)
+ clampb[CLAMPBOFF+j] = byte j;
+ for(j=0; j<CLAMPBOFF; j++)
+ clampb[CLAMPBOFF+256+j] = byte 16rFF;
+}
+
+
+# Fills in pixels (x,y) for x = minx=8*Hmax*(mcu%nacross), minx+1, ..., minx+8*Hmax-1 (or h.X-1, if less)
+# and for y = miny=8*Vmax*(mcu/nacross), miny+1, ..., miny+8*Vmax-1 (or h.Y-1, if less)
+colormap(h: ref Jpegstate, chans: array of array of byte, data0, data1, data2: array of array of int, mcu, nacross, Hmax, Vmax: int, H, V: array of int)
+{
+ rpic := chans[0];
+ gpic := chans[1];
+ bpic := chans[2];
+ minx := 8*Hmax*(mcu%nacross);
+ dx := 8*Hmax;
+ if(minx+dx > h.X)
+ dx = h.X-minx;
+ miny := 8*Vmax*(mcu/nacross);
+ dy := 8*Vmax;
+ if(miny+dy > h.Y)
+ dy = h.Y-miny;
+ pici := miny*h.X+minx;
+ H0 := H[0];
+ H1 := H[1];
+ H2 := H[2];
+ for(y:=0; y<dy; y++) {
+ t := y*V[0];
+ b0 := H0*(t/(8*Vmax));
+ y0 := 8*((t/Vmax)&7);
+ t = y*V[1];
+ b1 := H1*(t/(8*Vmax));
+ y1 := 8*((t/Vmax)&7);
+ t = y*V[2];
+ b2 := H2*(t/(8*Vmax));
+ y2 := 8*((t/Vmax)&7);
+ x0 := 0;
+ x1 := 0;
+ x2 := 0;
+ for(x:=0; x<dx; x++) {
+ rpic[pici+x] = clampb[data0[b0][y0+x0++*H0/Hmax] + 128 + CLAMPBOFF];
+ gpic[pici+x] = clampb[data1[b1][y1+x1++*H1/Hmax] + 128 + CLAMPBOFF];
+ bpic[pici+x] = clampb[data2[b2][y2+x2++*H2/Hmax] + 128 + CLAMPBOFF];
+ if(x0*H0/Hmax >= 8){
+ x0 = 0;
+ b0++;
+ }
+ if(x1*H1/Hmax >= 8){
+ x1 = 0;
+ b1++;
+ }
+ if(x2*H2/Hmax >= 8){
+ x2 = 0;
+ b2++;
+ }
+ }
+ pici += h.X;
+ }
+}
+
+# decode next 8-bit value from entropy-coded input. chart F-26
+jdecode(is: ref ImageSource, t: ref Huffman): int
+{
+ h := is.jstate;
+ maxcode := t.maxcode;
+ if(h.cnt < 8)
+ jnextbyte(is);
+ # fast lookup
+ code := (h.sr>>(h.cnt-8))&16rFF;
+ v := t.value[code];
+ if(v >= 0){
+ h.cnt -= t.shift[code];
+ return v;
+ }
+
+ h.cnt -= 8;
+ if(h.cnt == 0)
+ jnextbyte(is);
+ h.cnt--;
+ cnt := h.cnt;
+ m := 1<<cnt;
+ sr := h.sr;
+ code <<= 1;
+ i := 9;
+ for(;;i++){
+ if(sr & m)
+ code |= 1;
+ if(code <= maxcode[i])
+ break;
+ code <<= 1;
+ m >>= 1;
+ if(m == 0){
+ sr = jnextbyte(is);
+ m = 16r80;
+ cnt = 8;
+ }
+ cnt--;
+ }
+ h.cnt = cnt;
+ return t.val[t.valptr[i]+(code-t.mincode[i])];
+}
+
+# load next byte of input
+jnextbyte(is: ref ImageSource): int
+{
+ b :=getc(is);
+
+ if(b == 16rFF) {
+ b2 :=getc(is);
+ if(b2 != 0) {
+ if(b2 == int DNL)
+ sys->print("Error: Jpeg DNL marker unimplemented");
+ # decoder is reading into marker; satisfy it and restore state
+ ungetc2(is, byte b);
+ }
+ }
+ h := is.jstate;
+ h.cnt += 8;
+ h.sr = (h.sr<<8)| b;
+ return b;
+}
+
+ungetc2(is: ref ImageSource, nil: byte)
+{
+ if(is.i < 2) {
+ if(is.i != 1)
+ sys->print("Error: EXInternal: ungetc2 past beginning of buffer");
+ is.i = 0;
+ }
+ else
+ is.i -= 2;
+}
+
+
+getc(is: ref ImageSource) : int
+{
+ if(is.i >= len is.data) {
+ sys->print("Error: premature eof");
+ }
+ if (is.i >= slowread)
+ wait4data(is.i);
+ return int is.data[is.i++];
+}
+
+# like jnextbyte, but look for marker too
+jnextborm(is: ref ImageSource): int
+{
+ b :=getc(is);
+
+ if(b == 16rFF)
+ return b;
+ h := is.jstate;
+ h.cnt += 8;
+ h.sr = (h.sr<<8)| b;
+ return b;
+}
+
+# return next s bits of input, MSB first, and level shift it
+jreceive(is: ref ImageSource, s: int): int
+{
+ h := is.jstate;
+ while(h.cnt < s)
+ jnextbyte(is);
+ h.cnt -= s;
+ v := h.sr >> h.cnt;
+ m := (1<<s);
+ v &= m-1;
+ # level shift
+ if(v < (m>>1))
+ v += ~(m-1)+1;
+ return v;
+}
+
+nibbles(c: int) : (int, int)
+{
+ return (c>>4, c&15);
+
+}
+
+# Scaled integer implementation.
+# inverse two dimensional DCT, Chen-Wang algorithm
+# (IEEE ASSP-32, pp. 803-816, Aug. 1984)
+# 32-bit integer arithmetic (8 bit coefficients)
+# 11 mults, 29 adds per DCT
+#
+# coefficients extended to 12 bit for IEEE1180-1990
+# compliance
+
+W1: con 2841; # 2048*sqrt(2)*cos(1*pi/16)
+W2: con 2676; # 2048*sqrt(2)*cos(2*pi/16)
+W3: con 2408; # 2048*sqrt(2)*cos(3*pi/16)
+W5: con 1609; # 2048*sqrt(2)*cos(5*pi/16)
+W6: con 1108; # 2048*sqrt(2)*cos(6*pi/16)
+W7: con 565; # 2048*sqrt(2)*cos(7*pi/16)
+
+W1pW7: con 3406; # W1+W7
+W1mW7: con 2276; # W1-W7
+W3pW5: con 4017; # W3+W5
+W3mW5: con 799; # W3-W5
+W2pW6: con 3784; # W2+W6
+W2mW6: con 1567; # W2-W6
+
+R2: con 181; # 256/sqrt(2)
+
+idct(b: array of int)
+{
+ # transform horizontally
+ for(y:=0; y<8; y++){
+ eighty := y<<3;
+ # if all non-DC components are zero, just propagate the DC term
+ if(b[eighty+1]==0)
+ if(b[eighty+2]==0 && b[eighty+3]==0)
+ if(b[eighty+4]==0 && b[eighty+5]==0)
+ if(b[eighty+6]==0 && b[eighty+7]==0){
+ v := b[eighty]<<3;
+ b[eighty+0] = v;
+ b[eighty+1] = v;
+ b[eighty+2] = v;
+ b[eighty+3] = v;
+ b[eighty+4] = v;
+ b[eighty+5] = v;
+ b[eighty+6] = v;
+ b[eighty+7] = v;
+ continue;
+ }
+ # prescale
+ x0 := (b[eighty+0]<<11)+128;
+ x1 := b[eighty+4]<<11;
+ x2 := b[eighty+6];
+ x3 := b[eighty+2];
+ x4 := b[eighty+1];
+ x5 := b[eighty+7];
+ x6 := b[eighty+5];
+ x7 := b[eighty+3];
+ # first stage
+ x8 := W7*(x4+x5);
+ x4 = x8 + W1mW7*x4;
+ x5 = x8 - W1pW7*x5;
+ x8 = W3*(x6+x7);
+ x6 = x8 - W3mW5*x6;
+ x7 = x8 - W3pW5*x7;
+ # second stage
+ x8 = x0 + x1;
+ x0 -= x1;
+ x1 = W6*(x3+x2);
+ x2 = x1 - W2pW6*x2;
+ x3 = x1 + W2mW6*x3;
+ x1 = x4 + x6;
+ x4 -= x6;
+ x6 = x5 + x7;
+ x5 -= x7;
+ # third stage
+ x7 = x8 + x3;
+ x8 -= x3;
+ x3 = x0 + x2;
+ x0 -= x2;
+ x2 = (R2*(x4+x5)+128)>>8;
+ x4 = (R2*(x4-x5)+128)>>8;
+ # fourth stage
+ b[eighty+0] = (x7+x1)>>8;
+ b[eighty+1] = (x3+x2)>>8;
+ b[eighty+2] = (x0+x4)>>8;
+ b[eighty+3] = (x8+x6)>>8;
+ b[eighty+4] = (x8-x6)>>8;
+ b[eighty+5] = (x0-x4)>>8;
+ b[eighty+6] = (x3-x2)>>8;
+ b[eighty+7] = (x7-x1)>>8;
+ }
+ # transform vertically
+ for(x:=0; x<8; x++){
+ # if all non-DC components are zero, just propagate the DC term
+ if(b[x+8*1]==0)
+ if(b[x+8*2]==0 && b[x+8*3]==0)
+ if(b[x+8*4]==0 && b[x+8*5]==0)
+ if(b[x+8*6]==0 && b[x+8*7]==0){
+ v := (b[x+8*0]+32)>>6;
+ b[x+8*0] = v;
+ b[x+8*1] = v;
+ b[x+8*2] = v;
+ b[x+8*3] = v;
+ b[x+8*4] = v;
+ b[x+8*5] = v;
+ b[x+8*6] = v;
+ b[x+8*7] = v;
+ continue;
+ }
+ # prescale
+ x0 := (b[x+8*0]<<8)+8192;
+ x1 := b[x+8*4]<<8;
+ x2 := b[x+8*6];
+ x3 := b[x+8*2];
+ x4 := b[x+8*1];
+ x5 := b[x+8*7];
+ x6 := b[x+8*5];
+ x7 := b[x+8*3];
+ # first stage
+ x8 := W7*(x4+x5) + 4;
+ x4 = (x8+W1mW7*x4)>>3;
+ x5 = (x8-W1pW7*x5)>>3;
+ x8 = W3*(x6+x7) + 4;
+ x6 = (x8-W3mW5*x6)>>3;
+ x7 = (x8-W3pW5*x7)>>3;
+ # second stage
+ x8 = x0 + x1;
+ x0 -= x1;
+ x1 = W6*(x3+x2) + 4;
+ x2 = (x1-W2pW6*x2)>>3;
+ x3 = (x1+W2mW6*x3)>>3;
+ x1 = x4 + x6;
+ x4 -= x6;
+ x6 = x5 + x7;
+ x5 -= x7;
+ # third stage
+ x7 = x8 + x3;
+ x8 -= x3;
+ x3 = x0 + x2;
+ x0 -= x2;
+ x2 = (R2*(x4+x5)+128)>>8;
+ x4 = (R2*(x4-x5)+128)>>8;
+ # fourth stage
+ b[x+8*0] = (x7+x1)>>14;
+ b[x+8*1] = (x3+x2)>>14;
+ b[x+8*2] = (x0+x4)>>14;
+ b[x+8*3] = (x8+x6)>>14;
+ b[x+8*4] = (x8-x6)>>14;
+ b[x+8*5] = (x0-x4)>>14;
+ b[x+8*6] = (x3-x2)>>14;
+ b[x+8*7] = (x7-x1)>>14;
+ }
+}
+
+resample(src: array of byte, sw, sh: int, dw, dh: int) : array of byte
+{
+ if(src == nil || sw == 0 || sh == 0 || dw == 0 || dh == 0)
+ return src;
+ xfac := real sw / real dw;
+ yfac := real sh / real dh;
+ totpix := dw*dh;
+ dst := array[totpix] of byte;
+ dindex := 0;
+
+ # precompute index in src row corresponding to each index in dst row
+ sindices := array[dw] of int;
+ dx := 0.0;
+ for(x := 0; x < dw; x++) {
+ sx := int dx;
+ dx += xfac;
+ if(sx >= sw)
+ sx = sw-1;
+ sindices[x] = sx;
+ }
+ dy := 0.0;
+ for(y := 0; y < dh; y++) {
+ sy := int dy;
+ dy += yfac;
+ if(sy >= sh)
+ sy = sh-1;
+ soffset := sy * sw;
+ for(x = 0; x < dw; x++)
+ dst[dindex++] = src[soffset + sindices[x]];
+ }
+
+ return dst;
+}
+
+Cr2r := array [256] of {
+ -179, -178, -177, -175, -174, -172, -171, -170, -168, -167, -165, -164, -163, -161, -160, -158,
+ -157, -156, -154, -153, -151, -150, -149, -147, -146, -144, -143, -142, -140, -139, -137, -136,
+ -135, -133, -132, -130, -129, -128, -126, -125, -123, -122, -121, -119, -118, -116, -115, -114,
+ -112, -111, -109, -108, -107, -105, -104, -102, -101, -100, -98, -97, -95, -94, -93, -91,
+ -90, -88, -87, -86, -84, -83, -81, -80, -79, -77, -76, -74, -73, -72, -70, -69,
+ -67, -66, -64, -63, -62, -60, -59, -57, -56, -55, -53, -52, -50, -49, -48, -46,
+ -45, -43, -42, -41, -39, -38, -36, -35, -34, -32, -31, -29, -28, -27, -25, -24,
+ -22, -21, -20, -18, -17, -15, -14, -13, -11, -10, -8, -7, -6, -4, -3, -1,
+ 0, 1, 3, 4, 6, 7, 8, 10, 11, 13, 14, 15, 17, 18, 20, 21,
+ 22, 24, 25, 27, 28, 29, 31, 32, 34, 35, 36, 38, 39, 41, 42, 43,
+ 45, 46, 48, 49, 50, 52, 53, 55, 56, 57, 59, 60, 62, 63, 64, 66,
+ 67, 69, 70, 72, 73, 74, 76, 77, 79, 80, 81, 83, 84, 86, 87, 88,
+ 90, 91, 93, 94, 95, 97, 98, 100, 101, 102, 104, 105, 107, 108, 109, 111,
+ 112, 114, 115, 116, 118, 119, 121, 122, 123, 125, 126, 128, 129, 130, 132, 133,
+ 135, 136, 137, 139, 140, 142, 143, 144, 146, 147, 149, 150, 151, 153, 154, 156,
+ 157, 158, 160, 161, 163, 164, 165, 167, 168, 170, 171, 172, 174, 175, 177, 178,
+};
+
+Cr2g := array [256] of {
+ -91, -91, -90, -89, -89, -88, -87, -86, -86, -85, -84, -84, -83, -82, -81, -81,
+ -80, -79, -79, -78, -77, -76, -76, -75, -74, -74, -73, -72, -71, -71, -70, -69,
+ -69, -68, -67, -66, -66, -65, -64, -64, -63, -62, -61, -61, -60, -59, -59, -58,
+ -57, -56, -56, -55, -54, -54, -53, -52, -51, -51, -50, -49, -49, -48, -47, -46,
+ -46, -45, -44, -44, -43, -42, -41, -41, -40, -39, -39, -38, -37, -36, -36, -35,
+ -34, -34, -33, -32, -31, -31, -30, -29, -29, -28, -27, -26, -26, -25, -24, -24,
+ -23, -22, -21, -21, -20, -19, -19, -18, -17, -16, -16, -15, -14, -14, -13, -12,
+ -11, -11, -10, -9, -9, -8, -7, -6, -6, -5, -4, -4, -3, -2, -1, -1,
+ 0, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+ 11, 12, 13, 14, 14, 15, 16, 16, 17, 18, 19, 19, 20, 21, 21, 22,
+ 23, 24, 24, 25, 26, 26, 27, 28, 29, 29, 30, 31, 31, 32, 33, 34,
+ 34, 35, 36, 36, 37, 38, 39, 39, 40, 41, 41, 42, 43, 44, 44, 45,
+ 46, 46, 47, 48, 49, 49, 50, 51, 51, 52, 53, 54, 54, 55, 56, 56,
+ 57, 58, 59, 59, 60, 61, 61, 62, 63, 64, 64, 65, 66, 66, 67, 68,
+ 69, 69, 70, 71, 71, 72, 73, 74, 74, 75, 76, 76, 77, 78, 79, 79,
+ 80, 81, 81, 82, 83, 84, 84, 85, 86, 86, 87, 88, 89, 89, 90, 91,
+};
+
+Cb2g := array [256] of {
+ -44, -44, -43, -43, -43, -42, -42, -42, -41, -41, -41, -40, -40, -40, -39, -39,
+ -39, -38, -38, -38, -37, -37, -36, -36, -36, -35, -35, -35, -34, -34, -34, -33,
+ -33, -33, -32, -32, -32, -31, -31, -31, -30, -30, -30, -29, -29, -29, -28, -28,
+ -28, -27, -27, -26, -26, -26, -25, -25, -25, -24, -24, -24, -23, -23, -23, -22,
+ -22, -22, -21, -21, -21, -20, -20, -20, -19, -19, -19, -18, -18, -18, -17, -17,
+ -17, -16, -16, -15, -15, -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -11,
+ -11, -11, -10, -10, -10, -9, -9, -9, -8, -8, -8, -7, -7, -7, -6, -6,
+ -6, -5, -5, -4, -4, -4, -3, -3, -3, -2, -2, -2, -1, -1, -1, 0,
+ 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5,
+ 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11,
+ 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16,
+ 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22,
+ 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27,
+ 28, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33,
+ 33, 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 37, 37, 38, 38, 38,
+ 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42, 43, 43, 43, 44,
+};
+
+Cb2b := array [256] of {
+ -227, -225, -223, -222, -220, -218, -216, -214, -213, -211, -209, -207, -206, -204, -202, -200,
+ -198, -197, -195, -193, -191, -190, -188, -186, -184, -183, -181, -179, -177, -175, -174, -172,
+ -170, -168, -167, -165, -163, -161, -159, -158, -156, -154, -152, -151, -149, -147, -145, -144,
+ -142, -140, -138, -136, -135, -133, -131, -129, -128, -126, -124, -122, -120, -119, -117, -115,
+ -113, -112, -110, -108, -106, -105, -103, -101, -99, -97, -96, -94, -92, -90, -89, -87,
+ -85, -83, -82, -80, -78, -76, -74, -73, -71, -69, -67, -66, -64, -62, -60, -58,
+ -57, -55, -53, -51, -50, -48, -46, -44, -43, -41, -39, -37, -35, -34, -32, -30,
+ -28, -27, -25, -23, -21, -19, -18, -16, -14, -12, -11, -9, -7, -5, -4, -2,
+ 0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 18, 19, 21, 23, 25, 27,
+ 28, 30, 32, 34, 35, 37, 39, 41, 43, 44, 46, 48, 50, 51, 53, 55,
+ 57, 58, 60, 62, 64, 66, 67, 69, 71, 73, 74, 76, 78, 80, 82, 83,
+ 85, 87, 89, 90, 92, 94, 96, 97, 99, 101, 103, 105, 106, 108, 110, 112,
+ 113, 115, 117, 119, 120, 122, 124, 126, 128, 129, 131, 133, 135, 136, 138, 140,
+ 142, 144, 145, 147, 149, 151, 152, 154, 156, 158, 159, 161, 163, 165, 167, 168,
+ 170, 172, 174, 175, 177, 179, 181, 183, 184, 186, 188, 190, 191, 193, 195, 197,
+ 198, 200, 202, 204, 206, 207, 209, 211, 213, 214, 216, 218, 220, 222, 223, 225,
+};