summaryrefslogtreecommitdiff
path: root/appl/wm/brutus/image.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/wm/brutus/image.b')
-rw-r--r--appl/wm/brutus/image.b259
1 files changed, 259 insertions, 0 deletions
diff --git a/appl/wm/brutus/image.b b/appl/wm/brutus/image.b
new file mode 100644
index 00000000..906c668d
--- /dev/null
+++ b/appl/wm/brutus/image.b
@@ -0,0 +1,259 @@
+implement Brutusext;
+
+# <Extension image imagefile>
+
+Name: con "Brutus image";
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+ draw: Draw;
+ Context, Image, Display, Rect: import draw;
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "imagefile.m";
+ imageremap: Imageremap;
+ readgif: RImagefile;
+ readjpg: RImagefile;
+
+include "tk.m";
+ tk: Tk;
+
+include "tkclient.m";
+ tkclient: Tkclient;
+
+include "pslib.m";
+ pslib: Pslib;
+
+include "brutus.m";
+include "brutusext.m";
+
+stderr: ref Sys->FD;
+
+Cache: adt
+{
+ args: string;
+ name: string;
+ r: Rect;
+};
+
+init(s: Sys, d: Draw, b: Bufio, t: Tk, w: Tkclient)
+{
+ sys = s;
+ draw = d;
+ bufio = b;
+ tk = t;
+ tkclient = w;
+ imageremap = load Imageremap Imageremap->PATH;
+ stderr = sys->fildes(2);
+}
+
+cache: list of ref Cache;
+
+create(parent: string, t: ref Tk->Toplevel, name, args: string): string
+{
+ if(imageremap == nil)
+ return sys->sprint(Name + ": can't load remap: %r");
+ display := t.image.display;
+ file := args;
+
+ for(cl:=cache; cl!=nil; cl=tl cl)
+ if((hd cl).args == args)
+ break;
+
+ c: ref Cache;
+ if(cl != nil)
+ c = hd cl;
+ else{
+ (im, mask, err) := loadimage(display, parent, file);
+ if(err != "")
+ return err;
+ imagename := name+file;
+ err = tk->cmd(t, "image create bitmap "+imagename);
+ if(len err > 0 && err[0] == '!')
+ return err;
+ err = tk->putimage(t, imagename, im, mask);
+ if(len err > 0 && err[0] == '!')
+ return err;
+ c = ref Cache(args, imagename, im.r);
+ cache = c :: cache;
+ }
+
+ err := tk->cmd(t, "canvas "+name+" -height "+string c.r.dy()+" -width "+string c.r.dx());
+ if(len err > 0 && err[0] == '!')
+ return err;
+ err = tk->cmd(t, name+" create image 0 0 -anchor nw -image "+c.name);
+
+ return "";
+}
+
+loadimage(display: ref Display, parent, file: string) : (ref Image, ref Image, string)
+{
+ im := display.open(fullname(parent, file));
+ mask: ref Image;
+
+ if(im == nil){
+ fd := bufio->open(fullname(parent, file), Bufio->OREAD);
+ if(fd == nil)
+ return (nil, nil, sys->sprint(Name + ": can't open %s: %r", file));
+
+ mod := filetype(file, fd);
+ if(mod == nil)
+ return (nil, nil, sys->sprint(Name + ": can't find decoder module for %s: %r", file));
+
+ (ri, err) := mod->read(fd);
+ if(ri == nil)
+ return (nil, nil, sys->sprint(Name + ": %s: %s", file, err));
+ if(err != "")
+ sys->fprint(stderr, Name + ": %s: %s", file, err);
+ mask = transparency(display, ri);
+
+ # if transparency is enabled, errdiff==1 is probably a mistake,
+ # but there's no easy solution.
+ (im, err) = imageremap->remap(ri, display, 1);
+ if(im == nil)
+ return (nil, nil, sys->sprint(Name+": remap %s: %s\n", file, err));
+ if(err != "")
+ sys->fprint(stderr, Name+": remap %s: %s\n", file, err);
+ ri = nil;
+ }
+ return(im, mask, "");
+}
+
+cook(parent: string, fmt: int, args: string): (ref Brutusext->Celem, string)
+{
+ file := args;
+ ans : ref Brutusext->Celem = nil;
+ if(fmt == Brutusext->FHtml) {
+ s := "<IMG SRC=\"" + file + "\">";
+ ans = ref Brutusext->Celem(Brutusext->Special, s, nil, nil, nil, nil);
+ }
+ else {
+ (rc, dir) := sys->stat(file);
+ if(rc < 0)
+ return (nil, "can't find " + file);
+ mtime := dir.mtime;
+
+ # psfile name: in dir of file, with .ps suffix
+ psfile := file;
+ for(i := (len psfile)-1; i >= 0; i--) {
+ if(psfile[i] == '.') {
+ psfile = psfile[0:i];
+ break;
+ }
+ }
+ psfile = psfile + ".ps";
+ (rc, dir) = sys->stat(psfile);
+ if(rc < 0 || dir.mtime < mtime) {
+ iob := bufio->create(psfile, Bufio->OWRITE, 8r664);
+ if(iob == nil)
+ return (nil, "can't create " + psfile);
+
+ display := draw->Display.allocate("");
+ (im, mask, err) := loadimage(display, parent, file);
+ if(err != "")
+ return (nil, err);
+ pslib = load Pslib Pslib->PATH;
+ if(pslib == nil)
+ return (nil, "can't load Pslib");
+ pslib->init(bufio);
+ pslib->writeimage(iob, im, 100);
+ iob.close();
+ }
+ s := "\\epsfbox{" + psfile + "}\n";
+ ans = ref Brutusext->Celem(Brutusext->Special, s, nil, nil, nil, nil);
+ }
+ return (ans, "");
+}
+
+fullname(parent, file: string): string
+{
+ if(len parent==0 || (len file>0 && (file[0]=='/' || file[0]=='#')))
+ return file;
+
+ for(i:=len parent-1; i>=0; i--)
+ if(parent[i] == '/')
+ return parent[0:i+1] + file;
+ return file;
+}
+
+#
+# rest of this is all borrowed from wm/view.
+# should probably be packaged - perhaps in RImagefile?
+#
+filetype(file: string, fd: ref Iobuf): RImagefile
+{
+ if(len file>4 && file[len file-4:]==".gif")
+ return loadgif();
+ if(len file>4 && file[len file-4:]==".jpg")
+ return loadjpg();
+
+ # sniff the header looking for a magic number
+ buf := array[20] of byte;
+ if(fd.read(buf, len buf) != len buf){
+ sys->fprint(stderr, "View: can't read %s: %r\n", file);
+ return nil;
+ }
+ fd.seek(big 0, 0);
+ if(string buf[0:6]=="GIF87a" || string buf[0:6]=="GIF89a")
+ return loadgif();
+ jpmagic := array[] of {byte 16rFF, byte 16rD8, byte 16rFF, byte 16rE0,
+ byte 0, byte 0, byte 'J', byte 'F', byte 'I', byte 'F', byte 0};
+ for(i:=0; i<len jpmagic; i++)
+ if(jpmagic[i]>byte 0 && buf[i]!=jpmagic[i])
+ break;
+ if(i == len jpmagic)
+ return loadjpg();
+ return nil;
+}
+
+loadgif(): RImagefile
+{
+ if(readgif == nil){
+ readgif = load RImagefile RImagefile->READGIFPATH;
+ if(readgif == nil)
+ sys->fprint(stderr, "Brutus image: can't load readgif: %r\n");
+ else
+ readgif->init(bufio);
+ }
+ return readgif;
+}
+
+loadjpg(): RImagefile
+{
+ if(readjpg == nil){
+ readjpg = load RImagefile RImagefile->READJPGPATH;
+ if(readjpg == nil)
+ sys->fprint(stderr, "Brutus image: can't load readjpg: %r\n");
+ else
+ readjpg->init(bufio);
+ }
+ return readjpg;
+}
+
+transparency(display: ref Display, r: ref RImagefile->Rawimage): ref Image
+{
+ if(r.transp == 0)
+ return nil;
+ if(r.nchans != 1)
+ return nil;
+ i := display.newimage(r.r, display.image.chans, 0, 0);
+ if(i == nil){
+ return nil;
+ }
+ pic := r.chans[0];
+ npic := len pic;
+ mpic := array[npic] of byte;
+ index := r.trindex;
+ for(j:=0; j<npic; j++)
+ if(pic[j] == index)
+ mpic[j] = byte 0;
+ else
+ mpic[j] = byte 16rFF;
+ i.writepixels(i.r, mpic);
+ return i;
+}