implement PsLib; include "sys.m"; sys: Sys; include "draw.m"; draw : Draw; Image, Display,Rect,Point : import draw; include "bufio.m"; bufmod : Bufio; include "tk.m"; tk: Tk; Toplevel: import tk; Iobuf : import bufmod; include "string.m"; str : String; include "daytime.m"; time : Daytime; include "pslib.m"; ASCII,RUNE,IMAGE : con iota; iteminfo : adt { itype : int; offset : int; # offset from the start of line. width : int; # width.... ascent : int; # ascent of the item font : int; # font line : int; # line its on buf : string; }; lineinfo : adt { xorg : int; yorg : int; width : int; height : int; ascent : int; }; font_arr := array[256] of {* => (-1,"")}; remap := array[20] of (string,string); PXPI : con 100; PTPI : con 72; boxes : int; totitems : int; totlines : int; curfont : int; def_font : string; def_font_type : int; curfonttype : int; pagestart : int; started : int; ctxt : ref Draw->Context; t : ref Toplevel; init(env : ref Draw->Context,d: ref Toplevel,box: int) : int { sys = load Sys Sys->PATH; str = load String String->PATH; draw = load Draw Draw->PATH; tk= load Tk Tk->PATH; bufmod = load Bufio Bufio->PATH; ctxt=env; t=d; totlines=0; totitems=0; pagestart=0; boxes=box; curfont=0; if (loadfonts()) return 1; started=1; return 0; } stats() : (int,int,int) { return (totitems,totlines,curfont); } loadfonts() : int { input : string; iob:=bufmod->open("/fonts/psrename",bufmod->OREAD); if (iob==nil) return 1; i:=0; while((input=iob.gets('\n'))!=nil){ (tkfont,psfont):=str->splitl(input," "); psfont=psfont[1:len psfont -1]; remap[i]=(tkfont,psfont); i++; } return 0; } preamble(ioutb : ref Iobuf, bb: Rect) : int { if (!started) return 1; time = load Daytime Daytime->PATH; fd := sys->open("/dev/user", sys->OREAD); if(fd == nil) { sys->print("failed to open /dev/user: %r"); return 1; } b := array[128] of byte; n := sys->read(fd, b, len b); b=b[0:n]; if(bb.max.x == 0 && bb.max.y == 0) { bb.max.x = 612; bb.max.y = 792; } ioutb.puts("%!PS-Adobe-3.0\n"); ioutb.puts(sys->sprint("%%%%Creator: PsLib 1.0 (%s)\n",string b)); ioutb.puts(sys->sprint("%%%%CreationDate: %s\n",time->time())); ioutb.puts("%%Pages: (atend) \n"); ioutb.puts(sys->sprint("%%%%BoundingBox: %d %d %d %d\n", bb.min.x, bb.min.y, bb.max.x, bb.max.y)); ioutb.puts("%%EndComments\n"); ioutb.puts("%%BeginProlog\n"); ioutb.puts("/doimage {\n"); ioutb.puts("/width exch def\n"); ioutb.puts("/height exch def\n"); ioutb.puts("/xstart exch def\n"); ioutb.puts("/ystart exch def\n"); ioutb.puts("/iwidth exch def\n"); ioutb.puts("/ascent exch def\n"); ioutb.puts("/iheight exch def\n"); ioutb.puts("gsave\n"); if(boxes) ioutb.puts("xstart ystart iwidth iheight rectstroke\n"); ioutb.puts("[/Indexed /DeviceRGB 255 \n"); ioutb.puts("\n"); ioutb.puts("] setcolorspace\n"); ioutb.puts("xstart ystart translate \n"); ioutb.puts("iwidth iheight scale \n"); ioutb.puts("<<\n"); ioutb.puts("/ImageType 1\n"); ioutb.puts("/Width width \n"); ioutb.puts("/Height height \n"); ioutb.puts("/BitsPerComponent 8 %bits/sample\n"); ioutb.puts("/Decode [0 255] % Inferno cmap\n"); ioutb.puts("/ImageMatrix [width 0 0 height neg 0 height]\n"); ioutb.puts("/DataSource currentfile /ASCII85Decode filter\n"); ioutb.puts(">> \n"); ioutb.puts("image\n"); ioutb.puts("grestore\n"); ioutb.puts("} def\n"); ioutb.puts("%%EndProlog\n"); return 0; } trailer(ioutb : ref Iobuf,pages : int) : int { if (!started) return 1; ioutb.puts("%%Trailer\n%%Pages: "+string pages+"\n%%EOF\n"); return 0; } printnewpage(pagenum : int,end : int, ioutb : ref Iobuf) { if (!started) return; pnum:=string pagenum; if (end){ # bounding box if (boxes){ ioutb.puts("18 18 moveto 594 18 lineto 594 774 lineto 18 774 lineto"+ " closepath stroke\n"); } ioutb.puts("showpage\n%%EndPage "+pnum+" "+pnum+"\n"); } else ioutb.puts("%%Page: "+pnum+" "+pnum+"\n"); } printimage(ioutb : ref Iobuf,line : lineinfo, imag : iteminfo) { RM:=612-18; #sys->print("Looking for [%s] of type [%s]\n",imag.buf,tk->cmd(t,"winfo class "+imag.buf)); im := ctxt.display.open("/icons/tk/inferno.bit"); if (line.xorg+imag.offset+imag.width>RM) imag.width=RM-line.xorg-imag.offset; ioutb.puts(sys->sprint("%d %d %d %d %d %d %d doimage\n",line.height,line.ascent,imag.width, line.yorg,line.xorg+imag.offset, im.r.dx(), im.r.dy())); imagebits(ioutb,im); } printline(ioutb: ref Iobuf,line : lineinfo,items : array of iteminfo) { ftype : int; fname : string; xstart:=line.xorg; wid:=xstart; # items if (len items == 0) return; ioutb.puts(sys->sprint("%d %d moveto\n",xstart+items[0].offset, line.yorg+line.height-line.ascent)); for(j:=0;jsprint("%s setfont\n",fname)); curfonttype=ftype; } ioutb.puts(sys->sprint("(%s) show\n",items[j].buf)); } wid=xstart+items[j].offset+items[j].width; } if (boxes) ioutb.puts(sys->sprint("%d %d %d %d rectstroke\n",line.xorg,line.yorg, wid,line.height)); } parseTkline(ioutb: ref Iobuf,input : string) : int { if (!started) return ERROR; thisline : lineinfo; PS:=792-18-18; # page size in points TM:=792-18; # top margin in points LM:=18; # left margin 1/4 in. in BM:=18; # bottom margin 1/4 in. in x : int; (x,input)=str->toint(input,10); thisline.xorg=(x*PXPI)/PTPI; (x,input)=str->toint(input,10); thisline.yorg=(x*PXPI)/PTPI; (x,input)=str->toint(input,10); thisline.width=(x*PXPI)/PTPI; (x,input)=str->toint(input,10); thisline.height=(x*PXPI)/PTPI; (x,input)=str->toint(input,10); thisline.ascent=(x*PXPI)/PTPI; (x,input)=str->toint(input,10); # thisline.numitems=x; if (thisline.width==0 || thisline.height==0) return OK; if (thisline.yorg+thisline.height-pagestart>PS){ pagestart=thisline.yorg; return NEWPAGE; # must resend this line.... } thisline.yorg=TM-thisline.yorg-thisline.height+pagestart; thisline.xorg+=LM; items:=getline(totlines,input); totitems+=len items; totlines++; printline(ioutb,thisline,items); return OK; } getfonts(input: string) : string { if (!started) return "Error"; tkfont,psfont : string; j : int; retval := ""; if (input[0]=='%') return ""; # get a line of the form # 5::/fonts/lucida/moo.16.font # translate it to... # 32 f32.16 # where 32==1<<5 and f32.16 is a postscript function that loads the # appropriate postscript font (from remap) # and writes it to fonts.... (bits,font):=str->toint(input,10); if (bits!=-1) bits=1<splitr(font,"."); (nil,font)=str->splitr(font[0:len font-1],"."); (fsize,nil):=str->toint(font,10); fsize=(PXPI*3*fsize)/(2*PTPI); enc_font:="f"+string bits+"."+string fsize; ps_func:="/"+enc_font+" /"+psfont+" findfont "+string fsize+ " scalefont def\n"; sy_font:="sy"+string fsize; xtra_func:="/"+sy_font+" /Symbol findfont "+string fsize+ " scalefont def\n"; for(i=0;i iteminfo(-1,-1,-1,-1,-1,-1,"")}; curitem:=0; while(input!=nil){ (nil,input)=str->splitl(input,"["); if (input==nil) break; com:=input[1]; input=input[2:]; case com { 'A' => nb=0; # get the width of the item (wid,input)=str->toint(input,10); #wid=(wid*PTPI)/PXPI; if (input[0]!='{'){ sys->print( "line %d item %d Bad Syntax : '{' expected\n", k,curitem); return nil; } # get the args. (args,input)=str->splitl(input,"}"); # get the flags. # assume there is only one int flag.. (flags,args)=str->toint(args[1:],16); if (args!=nil){ sys->print( "line %d item %d Bad Syntax args=%s\n", k,curitem,args); return nil; } if (flags<1024) flags=1; item_arr[curitem].font=flags; item_arr[curitem].offset=lw; item_arr[curitem].width=wid; lw+=wid; for(j=1;jlen input) input=input[j:]; item_arr[curitem].buf=lineval; item_arr[curitem].line=k; item_arr[curitem].itype=ASCII; curitem++; lineval=""; 'R' => nb=0; # get the width of the item (wid,input)=str->toint(input,10); if (input[0]!='{'){ sys->print("Bad Syntax : '{' expected\n"); return nil; } # get the args. (args,input)=str->splitl(input,"}"); # get the flags. # assume there is only one int flag.. (flags,args)=str->toint(args[1:],16); if (args!=nil){ sys->print( "line %d item %d Bad Syntax args=%s\n", k,curitem,args); return nil; } item_arr[curitem].font=flags; item_arr[curitem].offset=lw; item_arr[curitem].width=wid; lw+=wid; for(j=1;j # bullet lineval+="\\267 "; 169 => # copyright lineval+="\\251 "; curitem++; * => lineval[len lineval]=input[j]; } } if (j>len input) input=input[j:]; item_arr[curitem].buf=lineval; item_arr[curitem].line=k; item_arr[curitem].itype=RUNE; curitem++; lineval=""; 'N' or 'C'=> # next item for(j=0;jlen input) input=input[j:]; 'T' => (wid,input)=str->toint(input,10); item_arr[curitem].offset=lw; item_arr[curitem].width=wid; lw+=wid; lineval[len lineval]='\t'; # next item for(j=0;jlen input) input=input[j:]; item_arr[curitem].buf=lineval; item_arr[curitem].line=k; item_arr[curitem].itype=ASCII; curitem++; lineval=""; 'W' => (wid,input)=str->toint(input,10); item_arr[curitem].offset=lw; item_arr[curitem].width=wid; item_arr[curitem].itype=IMAGE; lw+=wid; # next item for(j=1;jlen input) input=input[j:]; curitem++; lineval=""; * => # next item for(j=0;jlen input) input=input[j:]; } } return item_arr[0:curitem]; } image2psfile(ioutb : ref Iobuf, im : ref Draw->Image, dpi: int) : int { r := im.r; if(r.min.x != 0 || r.min.y != 0) return ERROR; width := r.dx(); height := r.dy(); iwidth := width * 72 / dpi; iheight := height * 72 / dpi; xstart := 72; ystart := 720 - iheight; bbox := Rect(Point(xstart,ystart), Point(xstart+iwidth,ystart+iheight)); if(preamble(ioutb, bbox) != 0) return ERROR; ioutb.puts("%%Page: 1\n%%BeginPageSetup\n"); ioutb.puts("/pgsave save def\n"); ioutb.puts("%%EndPageSetup\n"); ioutb.puts(sys->sprint("%d 0 %d %d %d %d %d doimage\n", iheight, iwidth, ystart, xstart, height, width)); imagebits(ioutb, im); ioutb.puts("pgsave restore\nshowpage\n"); trailer(ioutb, 1); ioutb.flush(); return OK; } imagebits(ioutb : ref Iobuf, im : ref Draw->Image) { width:=im.r.dx(); height:=im.r.dy(); bps:=1<print("width=%d, height=%d, bits/pixel=%d\n",width,height,bps); arr:=array[(width*height*bps)/8] of byte; n:=im.readpixels(im.r,arr); # sys->print("%d bytes read\n",n); #To convert a pixel byte value v from a limbo image to #3 bytes (r,g,b), use: # (r,g,b) := d.cmap2rgb(v); #where d is a display pointer (e.g., from context.display where #context is the init arg). lsf:=0; for(i:=0;i80){ ioutb.puts("\n"); lsf=0; } } if(n-((n/4)*4)!=0){ foo:=array[4] of {byte 0}; foo[0:]=arr[(n/4)*4:]; ioutb.puts(cmap2ascii85(foo)); } ioutb.puts("~>\n"); ioutb.flush(); } cmap2ascii85(arr : array of byte) : string { b := array[4] of {big 0}; for(i:=0;i<4;i++) b[i]=big arr[i]; i1:=(b[0]<<24)+(b[1]<<16)+(b[2]<<8)+b[3]; c1:=sys->sprint("%c%c%c%c%c",'!'+int ((i1/big (85*85*85*85))%big 85), '!'+int ((i1/big (85*85*85))%big 85), '!'+int ((i1/big (85*85))% big 85), '!'+int ((i1/big 85)% big 85),'!'+int(i1% big 85)); if (c1=="!!!!!") c1="z"; return c1; }