summaryrefslogtreecommitdiff
path: root/appl/lib/readpicfile.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/lib/readpicfile.b')
-rw-r--r--appl/lib/readpicfile.b164
1 files changed, 164 insertions, 0 deletions
diff --git a/appl/lib/readpicfile.b b/appl/lib/readpicfile.b
new file mode 100644
index 00000000..a8983d24
--- /dev/null
+++ b/appl/lib/readpicfile.b
@@ -0,0 +1,164 @@
+implement RImagefile;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "imagefile.m";
+
+Header: adt
+{
+ fd: ref Iobuf;
+ ch: chan of (ref Rawimage, string);
+ # variables in i/o routines
+ buf: array of byte;
+ bufi: int;
+ nbuf: int;
+
+ TYPE: string;
+ CHAN: string;
+ NCHAN: string;
+ CMAP: int;
+
+ dx: int;
+ dy: int;
+};
+
+NBUF: con 8*1024;
+
+init(iomod: Bufio)
+{
+ if(sys == nil)
+ sys = load Sys Sys->PATH;
+ bufio = iomod;
+}
+
+read(fd: ref Iobuf): (ref Rawimage, string)
+{
+ # spawn a subprocess so I/O errors can clean up easily
+
+ ch := chan of (ref Rawimage, string);
+ spawn readslave(fd, ch);
+
+ return <-ch;
+}
+
+readmulti(fd: ref Iobuf): (array of ref Rawimage, string)
+{
+ (i, err) := read(fd);
+ if(i != nil){
+ a := array[1] of { i };
+ return (a, err);
+ }
+ return (nil, err);
+}
+
+readslave(fd: ref Iobuf, ch: chan of (ref Rawimage, string))
+{
+ (header, err) := header(fd, ch);
+ if(header == nil){
+ ch <-= (nil, err);
+ exit;
+ }
+
+ ch <-= image(header);
+}
+
+readerror(): string
+{
+ return sys->sprint("ReadPIC: read error: %r");
+}
+
+header(fd: ref Iobuf, ch: chan of (ref Rawimage, string)): (ref Header, string)
+{
+ h := ref Header;
+
+ h.fd = fd;
+ h.ch = ch;
+ h.CMAP = 0;
+ h.dx = 0;
+ h.dy = 0;
+ cantparse := "ReadPIC: can't parse header";
+ for(;;){
+ s := fd.gets('\n');
+ if(s==nil || s[len s-1]!='\n')
+ return (nil, cantparse);
+ if(s == "\n")
+ break;
+ addfield(h, s[0:len s-1]);
+ }
+ if(h.dx<=0 || h.dy<=0)
+ return (nil, "ReadPIC: empty picture or WINDOW not set");
+ return (h, nil);
+}
+
+addfield(h: ref Header, s: string)
+{
+ baddata := "ReadPIC: not a PIC header";
+ for(i:=0; i<len s; i++){
+ if(s[i] == '=')
+ break;
+ if(s[i]==0 || s[i]>16r7f){
+ h.ch <-= (nil, baddata);
+ exit;
+ }
+ }
+ if(i == len s){
+ h.ch <-= (nil, baddata);
+ exit;
+ }
+ case s[0:i]{
+ "TYPE" =>
+ h.TYPE = s[i+1:];
+ "CHAN" =>
+ h.CHAN = s[i+1:];
+ "NCHAN" =>
+ h.NCHAN = s[i+1:];
+ "CMAP" =>
+ h.CMAP = 1;
+ "WINDOW" =>
+ (n, l) := sys->tokenize(s[i+1:], " ");
+ if(n != 4){
+ h.ch <-= (nil, "ReadPIC: bad WINDOW specification");
+ exit;
+ }
+ x0 := int hd l;
+ l = tl l;
+ y0 := int hd l;
+ l = tl l;
+ h.dx = int hd l - x0;
+ l = tl l;
+ h.dy = int hd l - y0;
+ }
+}
+
+image(h: ref Header): (ref Rawimage, string)
+{
+ if(h.TYPE!="dump" || h.CHAN!="rgb" || h.NCHAN!="3" || h.CMAP)
+ return (nil, "ReadPIC: can't handle this type of picture");
+
+ i := ref Rawimage;
+ i.r = ((0,0), (h.dx, h.dy));
+ i.cmap = nil;
+ i.transp = 0;
+ i.trindex = byte 0;
+ i.nchans = int h.NCHAN;
+ i.chans = array[i.nchans] of array of byte;
+ for(j:=0; j<i.nchans; j++)
+ i.chans[j] = array[h.dx*h.dy] of byte;
+ i.chandesc = CRGB;
+ n := h.dx*h.dy;
+ b := array[i.nchans*n] of byte;
+ if(h.fd.read(b, len b) != len b)
+ return (nil, "ReadPIC: file too short");
+ l := 0;
+ for(j=0; j<n; j++)
+ for(k:=0; k<i.nchans; k++)
+ i.chans[k][j] = b[l++];
+ return (i, nil);
+}