implement WImagefile; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; Display, Image, Rect: import draw; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "imagefile.m"; Nhash: con 4001; Entry: adt { index: int; prefix: int; exten: int; next: cyclic ref Entry; }; IO: adt { fd: ref Iobuf; buf: array of byte; i: int; nbits: int; # bits in right side of shift register sreg: int; # shift register }; tbl: array of ref Entry; colormap: array of array of byte; init(iomod: Bufio) { if(sys == nil){ sys = load Sys Sys->PATH; draw = load Draw Draw->PATH; } bufio = iomod; } writeimage(fd: ref Iobuf, image: ref Image): string { inittbl(); writeheader(fd, image); writedescriptor(fd, image); err := writedata(fd, image); if(err != nil) return err; writetrailer(fd); fd.flush(); return err; } inittbl() { tbl = array[4096] of ref Entry; for(i:=0; i>8)); } # Get color map for all ldepths, in format suitable for writing out getcolormap(image: ref Draw->Image) { if(colormap != nil) return; colormap = array[4] of array of byte; display := image.display; colormap[3] = array[3*256] of byte; colormap[2] = array[3*16] of byte; colormap[1] = array[3*4] of byte; colormap[0] = array[3*2] of byte; c := colormap[3]; for(i:=0; i<256; i++){ (r, g, b) := display.cmap2rgb(i); c[3*i+0] = byte r; c[3*i+1] = byte g; c[3*i+2] = byte b; } c = colormap[2]; for(i=0; i<16; i++){ col := (i<<4)|i; (r, g, b) := display.cmap2rgb(col); c[3*i+0] = byte r; c[3*i+1] = byte g; c[3*i+2] = byte b; } c = colormap[1]; for(i=0; i<4; i++){ col := (i<<6)|(i<<4)|(i<<2)|i; (r, g, b) := display.cmap2rgb(col); c[3*i+0] = byte r; c[3*i+1] = byte g; c[3*i+2] = byte b; } c = colormap[0]; for(i=0; i<2; i++){ if(i == 0) col := 0; else col = 16rFF; (r, g, b) := display.cmap2rgb(col); c[3*i+0] = byte r; c[3*i+1] = byte g; c[3*i+2] = byte b; } } # Put n bits of c into output at io.buf[i]; output(io: ref IO, c, n: int) { if(c < 0){ if(io.nbits != 0) io.buf[io.i++] = byte io.sreg; io.fd.putb(byte io.i); io.fd.write(io.buf, io.i); io.nbits = 0; return; } if(io.nbits+n >= 31){ sys->print("panic: WriteGIF sr overflow\n"); exit; } io.sreg |= c<= 8){ io.buf[io.i++] = byte io.sreg; io.sreg >>= 8; io.nbits -= 8; } if(io.i >= 255){ io.fd.putb(byte 255); io.fd.write(io.buf, 255); io.buf[0:] = io.buf[255:io.i]; io.i -= 255; } } # LZW encoder encode(fd: ref Iobuf, image: ref Image): string { c, h, csize, prefix: int; e, oe: ref Entry; first := 1; ld := image.ldepth; # ldepth 0 must generate codesize 2 with values 0 and 1 (see the spec.) ld0 := ld; if(ld0 == 0) ld0 = 1; codesize := (1<>(3-image.ldepth)))] of byte; ndata := image.readpixels(image.r, data); if(ndata < 0) return sys->sprint("WriteGIF: readpixels: %r"); datai := 0; x := image.r.min.x; Init: for(;;){ csize = codesize+1; nentry := EOD+1; maxentry := (1<>ld))<>nbits & pm; h = prefix<<24 | c<<8; h %= Nhash; if(h < 0) h += Nhash; oe = nil; for(e = hash[h]; e!=nil; e=e.next){ if(e.prefix == prefix && e.exten == c){ if(oe != nil){ oe.next = e.next; e.next = hash[h]; hash[h] = e; } prefix = e.index; continue Next; } oe = e; } output(io, prefix, csize); early:=0; # peculiar tiff feature here for reference if(nentry == maxentry-early){ if(csize == 12){ nbits += codesize; # unget pixel x--; output(io, CTM, csize); continue Init; } csize++; maxentry = (1<