implement Images; include "draw.m"; draw : Draw; include "sys.m"; sys: Sys; include "bufio.m"; bufio: Bufio; Iobuf : import bufio; include "ppm.m"; ppm_header(width, height, format, maxval : int) : array of byte { return array of byte sys->sprint("P%d\n%d %d\n%d\n", format, width, height, maxval); } init(nil: ref Draw->Context, nil: list of string) { draw = load Draw Draw->PATH; sys = load Sys Sys->PATH; bufio = load Bufio Bufio->PATH; } new_rgba8(width, height : int) : ref Image { return ref Image(width, height, 6, 255, 3, ref Bitmap.rgba8(width, height, array [width * height * 4] of byte), big 0, nil); } create_ppm(i : ref Image, filename : string) { fd := sys->create(filename, sys->OWRITE, 8r666); if(fd == nil) raise "create file failed"; pick bm := i.bitmap { rgba8 => hdr := ppm_header(i.width, i.height, 6, 255); sys->write(fd, hdr, len hdr); rowbytes := i.width * 3; rgb := array[rowbytes] of byte; j, k : int; j = 0; for(y := 0; y < i.height; y++) { k = 0; for(x := 0; x < i.width; x++) { rgb[k++] = bm.pixels[j+2]; rgb[k++] = bm.pixels[j+1]; rgb[k++] = bm.pixels[j]; j+=4; } sys->write(fd, rgb, rowbytes); } * => raise "only 8bpp P6 ppm supported"; } } Image.open_ppm(f : self ref Image, filename : string) : ref sys->FD { hdr := ppm_header(f.width, f.height, f.format, f.maxval); f.dataoffset = big len hdr; f.fd = sys->open(filename, sys->ORDWR); return f.fd; } Image.write_to_ppm_pixel(f : self ref Image, x, y, v, channel : int) : int { bytespp := 0; mv := f.maxval; while(mv > 0) { bytespp++; mv >>= 8; } numchannels := 3; pixel := y * numchannels * f.width + x * numchannels; pixel += channel; pos := f.dataoffset + big bytespp * big pixel; sys->seek(f.fd, pos, sys->SEEKSTART); vb := array[bytespp] of byte; if(bytespp > 1) { for(i := 0; i < bytespp; i++) { vb[i] = (byte v) & byte 16rFF; v >>= 1; } } else { vb[0] = byte v; } return sys->write(f.fd, vb, len vb); }