1implement Pslib; 2 3include "sys.m"; 4 sys: Sys; 5 6include "draw.m"; 7 draw : Draw; 8Image, Display,Rect,Point : import draw; 9 10include "bufio.m"; 11 bufmod : Bufio; 12 13include "tk.m"; 14 tk: Tk; 15 Toplevel: import tk; 16 17Iobuf : import bufmod; 18 19include "string.m"; 20 str : String; 21 22include "daytime.m"; 23 time : Daytime; 24 25include "pslib.m"; 26 27# old module declaration. 28# this whole thing needs a revamp, so almost all the old external 29# linkages have been removed until there's time to do it properly. 30#Pslib : module 31#{ 32# PATH: con "/dis/lib/pslib.dis"; 33# 34# init: fn(env: ref Draw->Context, t: ref Tk->Toplevel, boxes: int, deb: int): string; 35# getfonts: fn(input: string): string; 36# preamble: fn(ioutb: ref Bufio->Iobuf, bbox: Draw->Rect): string; 37# trailer: fn(ioutb: ref Bufio->Iobuf, pages: int): string; 38# printnewpage: fn(pagenum: int, end: int, ioutb: ref Bufio->Iobuf); 39# parseTkline: fn(ioutb: ref Bufio->Iobuf, input: string): string; 40# stats: fn(): (int, int, int); 41# deffont: fn(): string; 42# image2psfile: fn(ioutb: ref Bufio->Iobuf, im: ref Draw->Image, dpi: int) : string; 43#}; 44 45ASCII,RUNE,IMAGE : con iota; 46 47Iteminfo : adt 48{ 49 itype: int; 50 offset: int; # offset from the start of line. 51 width: int; # width.... 52 ascent: int; # ascent of the item 53 font: int; # font 54 line : int; # line its on 55 buf : string; 56}; 57 58Lineinfo : adt 59{ 60 xorg: int; 61 yorg: int; 62 width: int; 63 height: int; 64 ascent: int; 65}; 66 67 68font_arr := array[256] of {* => (-1,"")}; 69remap := array[20] of (string,string); 70 71PXPI : con 100; 72PTPI : con 100; 73 74boxes: int; 75debug: int; 76totitems: int; 77totlines: int; 78curfont: int; 79def_font: string; 80def_font_type: int; 81curfonttype: int; 82pagestart: int; 83ctxt: ref Draw->Context; 84t: ref Toplevel; 85 86nomod(s: string) 87{ 88 sys->print("pslib: cannot load %s: %r\n", s); 89 raise "fail:bad module"; 90} 91 92init(bufio: Bufio) 93{ 94 sys = load Sys Sys->PATH; 95 draw = load Draw Draw->PATH; 96 tk= load Tk Tk->PATH; 97 if (tk == nil) 98 nomod(Tk->PATH); 99 str = load String String->PATH; 100 if (str == nil) 101 nomod(String->PATH); 102 bufmod = bufio; 103} 104 105 106oldinit(env: ref Draw->Context, d: ref Toplevel, nil: int,deb: int): string 107{ 108 sys = load Sys Sys->PATH; 109 str = load String String->PATH; 110 draw = load Draw Draw->PATH; 111 tk= load Tk Tk->PATH; 112 bufmod = load Bufio Bufio->PATH; 113 ctxt=env; 114 t=d; 115 debug = deb; 116 totlines=0; 117 totitems=0; 118 pagestart=0; 119 boxes=0; #box; 120 curfont=0; 121 e := loadfonts(); 122 if (e != "") 123 return e; 124 return ""; 125} 126 127stats(): (int,int,int) 128{ 129 return (totitems,totlines,curfont); 130} 131 132loadfonts() : string 133{ 134 input : string; 135 iob:=bufmod->open("/fonts/psrename",bufmod->OREAD); 136 if (iob==nil) 137 return sys->sprint("can't open /fonts/psrename: %r"); 138 i:=0; 139 while((input=iob.gets('\n'))!=nil){ 140 (tkfont,psfont):=str->splitl(input," "); 141 psfont=psfont[1:len psfont -1]; 142 remap[i]=(tkfont,psfont); 143 i++; 144 } 145 return ""; 146} 147 148preamble(ioutb: ref Iobuf, bb: Rect) 149{ 150 time = load Daytime Daytime->PATH; 151 username := ""; 152 fd := sys->open("/dev/user", sys->OREAD); 153 if(fd != nil) { 154 b := array[128] of byte; 155 n := sys->read(fd, b, len b); 156 b=b[0:n]; 157 username = string b; 158 fd = nil; 159 } 160 if(bb.max.x == 0 && bb.max.y == 0) { 161 bb.max.x = 612; 162 bb.max.y = 792; 163 } 164 ioutb.puts("%!PS-Adobe-3.0\n"); 165 ioutb.puts(sys->sprint("%%%%Creator: Pslib 1.0 (%s)\n",username)); 166 ioutb.puts(sys->sprint("%%%%CreationDate: %s\n",time->time())); 167 ioutb.puts("%%Pages: (atend) \n"); 168 ioutb.puts(sys->sprint("%%%%BoundingBox: %d %d %d %d\n", bb.min.x, bb.min.y, bb.max.x, bb.max.y)); 169 ioutb.puts("%%EndComments\n"); 170 ioutb.puts("%%BeginProlog\n"); 171 ioutb.puts("/doimage {\n"); 172 ioutb.puts("/bps exch def\n"); 173 ioutb.puts("/width exch def\n"); 174 ioutb.puts("/height exch def\n"); 175 ioutb.puts("/xstart exch def\n"); 176 ioutb.puts("/ystart exch def\n"); 177 ioutb.puts("/iwidth exch def\n"); 178 ioutb.puts("/ascent exch def\n"); 179 ioutb.puts("/iheight exch def\n"); 180 ioutb.puts("gsave\n"); 181 if(boxes) 182 ioutb.puts("xstart ystart iwidth iheight rectstroke\n"); 183 # if bps==8, use inferno colormap; else (bps < 8) it's grayscale 184 ioutb.puts("bps 8 eq\n"); 185 ioutb.puts("{\n"); 186 ioutb.puts("[/Indexed /DeviceRGB 255 \n"); 187 ioutb.puts("<ffffff ffffaa ffff55 ffff00 ffaaff ffaaaa ffaa55 ffaa00 ff55ff ff55aa ff5555 ff5500\n"); 188 ioutb.puts("ff00ff ff00aa ff0055 ff0000 ee0000 eeeeee eeee9e eeee4f eeee00 ee9eee ee9e9e ee9e4f\n"); 189 ioutb.puts("ee9e00 ee4fee ee4f9e ee4f4f ee4f00 ee00ee ee009e ee004f dd0049 dd0000 dddddd dddd93\n"); 190 ioutb.puts("dddd49 dddd00 dd93dd dd9393 dd9349 dd9300 dd49dd dd4993 dd4949 dd4900 dd00dd dd0093\n"); 191 ioutb.puts("cc0088 cc0044 cc0000 cccccc cccc88 cccc44 cccc00 cc88cc cc8888 cc8844 cc8800 cc44cc\n"); 192 ioutb.puts("cc4488 cc4444 cc4400 cc00cc aaffaa aaff55 aaff00 aaaaff bbbbbb bbbb5d bbbb00 aa55ff\n"); 193 ioutb.puts("bb5dbb bb5d5d bb5d00 aa00ff bb00bb bb005d bb0000 aaffff 9eeeee 9eee9e 9eee4f 9eee00\n"); 194 ioutb.puts("9e9eee aaaaaa aaaa55 aaaa00 9e4fee aa55aa aa5555 aa5500 9e00ee aa00aa aa0055 aa0000\n"); 195 ioutb.puts("990000 93dddd 93dd93 93dd49 93dd00 9393dd 999999 99994c 999900 9349dd 994c99 994c4c\n"); 196 ioutb.puts("994c00 9300dd 990099 99004c 880044 880000 88cccc 88cc88 88cc44 88cc00 8888cc 888888\n"); 197 ioutb.puts("888844 888800 8844cc 884488 884444 884400 8800cc 880088 55ff55 55ff00 55aaff 5dbbbb\n"); 198 ioutb.puts("5dbb5d 5dbb00 5555ff 5d5dbb 777777 777700 5500ff 5d00bb 770077 770000 55ffff 55ffaa\n"); 199 ioutb.puts("4fee9e 4fee4f 4fee00 4f9eee 55aaaa 55aa55 55aa00 4f4fee 5555aa 666666 666600 4f00ee\n"); 200 ioutb.puts("5500aa 660066 660000 4feeee 49dddd 49dd93 49dd49 49dd00 4993dd 4c9999 4c994c 4c9900\n"); 201 ioutb.puts("4949dd 4c4c99 555555 555500 4900dd 4c0099 550055 550000 440000 44cccc 44cc88 44cc44\n"); 202 ioutb.puts("44cc00 4488cc 448888 448844 448800 4444cc 444488 444444 444400 4400cc 440088 440044\n"); 203 ioutb.puts("00ff00 00aaff 00bbbb 00bb5d 00bb00 0055ff 005dbb 007777 007700 0000ff 0000bb 000077\n"); 204 ioutb.puts("333333 00ffff 00ffaa 00ff55 00ee4f 00ee00 009eee 00aaaa 00aa55 00aa00 004fee 0055aa\n"); 205 ioutb.puts("006666 006600 0000ee 0000aa 000066 222222 00eeee 00ee9e 00dd93 00dd49 00dd00 0093dd\n"); 206 ioutb.puts("009999 00994c 009900 0049dd 004c99 005555 005500 0000dd 000099 000055 111111 00dddd\n"); 207 ioutb.puts("00cccc 00cc88 00cc44 00cc00 0088cc 008888 008844 008800 0044cc 004488 004444 004400\n"); 208 ioutb.puts("0000cc 000088 000044 000000>\n"); 209 ioutb.puts("] setcolorspace\n"); 210 ioutb.puts("/decodemat [0 255] def\n"); 211 ioutb.puts("}\n"); 212 # else, bps != 8 213 ioutb.puts("{\n"); 214 ioutb.puts("[/DeviceGray] setcolorspace\n"); 215 ioutb.puts("/decodemat [1 0] def\n"); 216 ioutb.puts("}\n"); 217 ioutb.puts("ifelse\n"); 218 ioutb.puts("xstart ystart translate \n"); 219 ioutb.puts("iwidth iheight scale \n"); 220 ioutb.puts("<<\n"); 221 ioutb.puts("/ImageType 1\n"); 222 ioutb.puts("/Width width \n"); 223 ioutb.puts("/Height height \n"); 224 ioutb.puts("/BitsPerComponent bps %bits/sample\n"); 225 ioutb.puts("/Decode decodemat % Inferno cmap or DeviceGray value\n"); 226 ioutb.puts("/ImageMatrix [width 0 0 height neg 0 height]\n"); 227 ioutb.puts("/DataSource currentfile /ASCII85Decode filter\n"); 228 ioutb.puts(">> \n"); 229 ioutb.puts("image\n"); 230 ioutb.puts("grestore\n"); 231 ioutb.puts("} def\n"); 232 ioutb.puts("%%EndProlog\n"); 233} 234 235trailer(ioutb : ref Iobuf,pages : int) 236{ 237 ioutb.puts("%%Trailer\n%%Pages: "+string pages+"\n%%EOF\n"); 238} 239 240 241printnewpage(pagenum : int,end : int, ioutb : ref Iobuf) 242{ 243 pnum:=string pagenum; 244 if (end){ 245 # bounding box 246 if (boxes){ 247 ioutb.puts("18 18 moveto 594 18 lineto 594 774 lineto 18 774 lineto"+ 248 " closepath stroke\n"); 249 } 250 ioutb.puts("showpage\n%%EndPage "+pnum+" "+pnum+"\n"); 251 } else 252 ioutb.puts("%%Page: "+pnum+" "+pnum+"\n"); 253} 254 255printimage(ioutb: ref Iobuf, line: Lineinfo, imag: Iteminfo): (string,string) 256{ 257 RM:=612-18; 258 class:=tk->cmd(t,"winfo class "+imag.buf); 259#sys->print("Looking for [%s] of type [%s]\n",imag.buf,class); 260 if (line.xorg+imag.offset+imag.width>RM) 261 imag.width=RM-line.xorg-imag.offset; 262 case class { 263 "button" or "menubutton" => 264 # try to get the text out and print it.... 265 ioutb.puts(sys->sprint("%d %d moveto\n",line.xorg+imag.offset, 266 line.yorg)); 267 msg:=tk->cmd(t,sys->sprint("%s cget -text",imag.buf)); 268 ft:=tk->cmd(t,sys->sprint("%s cget -font",imag.buf)); 269 sys->print("font is [%s]\n",ft); 270 ioutb.puts(sys->sprint("%d %d %d %d rectstroke\n", 271 line.xorg+imag.offset,line.yorg,imag.width, 272 line.height)); 273 return (class,msg); 274 "label" => 275 (im,nil,nil) := tk->getimage(t,imag.buf); 276 if (im!=nil){ 277 bps := im.depth; 278 ioutb.puts(sys->sprint("%d %d %d %d %d %d %d %d doimage\n", 279 im.r.dy(),line.ascent,im.r.dx(),line.yorg, 280 line.xorg+imag.offset,im.r.dy(), im.r.dx(), bps)); 281 imagebits(ioutb,im); 282 } 283 return (class,""); 284 "entry" => 285 ioutb.puts(sys->sprint("%d %d moveto\n",line.xorg+imag.offset, 286 line.yorg)); 287 ioutb.puts(sys->sprint("%d %d %d %d rectstroke\n", 288 line.xorg+imag.offset,line.yorg,imag.width, 289 line.height)); 290 return (class,""); 291 * => 292 sys->print("Unhandled class [%s]\n",class); 293 return (class,"Error"); 294 295 } 296 return ("",""); 297} 298 299printline(ioutb: ref Iobuf,line : Lineinfo,items : array of Iteminfo) 300{ 301 xstart:=line.xorg; 302 wid:=xstart; 303 # items 304 if (len items == 0) return; 305 for(j:=0;j<len items;j++){ 306 msg:=""; 307 class:=""; 308 if (items[j].itype==IMAGE) 309 (class,msg)=printimage(ioutb,line,items[j]); 310 if (items[j].itype!=IMAGE || class=="button"|| class=="menubutton"){ 311 setfont(ioutb,items[j].font); 312 if (msg!=""){ 313 # position the text in the center of the label 314 # moveto curpoint 315 # (msg) stringwidth pop xstart sub 2 div 316 ioutb.puts(sys->sprint("%d %d moveto\n",xstart+items[j].offset, 317 line.yorg+line.height-line.ascent)); 318 ioutb.puts(sys->sprint("(%s) dup stringwidth pop 2 div", 319 msg)); 320 ioutb.puts(" 0 rmoveto show\n"); 321 } 322 else { 323 ioutb.puts(sys->sprint("%d %d moveto\n", 324 xstart+items[j].offset,line.yorg+line.height 325 -line.ascent)); 326 ioutb.puts(sys->sprint("(%s) show\n",items[j].buf)); 327 } 328 } 329 wid=xstart+items[j].offset+items[j].width; 330 } 331 if (boxes) 332 ioutb.puts(sys->sprint("%d %d %d %d rectstroke\n",line.xorg,line.yorg, 333 wid,line.height)); 334} 335 336setfont(ioutb: ref Iobuf, font: int) 337{ 338 ftype : int; 339 fname : string; 340 if ((curfonttype & font) != curfonttype){ 341 for(f:=0;f<curfont;f++){ 342 (ftype,fname)=font_arr[f]; 343 if ((ftype&font)==ftype) 344 break; 345 } 346 if (f==curfont){ 347 fname=def_font; 348 ftype=def_font_type; 349 } 350 ioutb.puts(sys->sprint("%s setfont\n",fname)); 351 curfonttype=ftype; 352 } 353} 354 355parseTkline(ioutb: ref Iobuf, input: string): string 356{ 357 thisline : Lineinfo; 358 PS:=792-18-18; # page size in points 359 TM:=792-18; # top margin in points 360 LM:=18; # left margin 1/4 in. in 361# BM:=18; # bottom margin 1/4 in. in 362 x : int; 363 (x,input)=str->toint(input,10); 364 thisline.xorg=(x*PTPI)/PXPI; 365 (x,input)=str->toint(input,10); 366 thisline.yorg=(x*PTPI)/PXPI; 367 (x,input)=str->toint(input,10); 368 thisline.width=(x*PTPI)/PXPI; 369 (x,input)=str->toint(input,10); 370 thisline.height=(x*PTPI)/PXPI; 371 (x,input)=str->toint(input,10); 372 thisline.ascent=(x*PTPI)/PXPI; 373 (x,input)=str->toint(input,10); 374 # thisline.numitems=x; 375 if (thisline.width==0 || thisline.height==0) 376 return ""; 377 if (thisline.yorg+thisline.height-pagestart>PS){ 378 pagestart=thisline.yorg; 379 return "newpage"; 380 # must resend this line.... 381 } 382 thisline.yorg=TM-thisline.yorg-thisline.height+pagestart; 383 thisline.xorg+=LM; 384 (items, err) :=getline(totlines,input); 385 if(err != nil) 386 return err; 387 totitems+=len items; 388 totlines++; 389 printline(ioutb,thisline,items); 390 return ""; 391} 392 393getfonts(input: string) : string 394{ 395 tkfont,psfont : string; 396 j : int; 397 retval := ""; 398 if (input[0]=='%') 399 return ""; 400 # get a line of the form 401 # 5::/fonts/lucida/moo.16.font 402 # translate it to... 403 # 32 f32.16 404 # where 32==1<<5 and f32.16 is a postscript function that loads the 405 # appropriate postscript font (from remap) 406 # and writes it to fonts.... 407 (bits,font):=str->toint(input,10); 408 if (bits!=-1) 409 bits=1<<bits; 410 else{ 411 bits=1; 412 def_font_type=bits; 413 curfonttype=def_font_type; 414 } 415 font=font[2:]; 416 for(i:=0;i<len remap;i++){ 417 (tkfont,psfont)=remap[i]; 418 if (tkfont==font) 419 break; 420 } 421 if (i==len remap) 422 psfont="Times-Roman"; 423 (font,nil)=str->splitr(font,"."); 424 (nil,font)=str->splitr(font[0:len font-1],"."); 425 (fsize,nil):=str->toint(font,10); 426 fsize=(PTPI*3*fsize)/(2*PXPI); 427 enc_font:="f"+string bits+"."+string fsize; 428 ps_func:="/"+enc_font+" /"+psfont+" findfont "+string fsize+ 429 " scalefont def\n"; 430 sy_font:="sy"+string fsize; 431 xtra_func:="/"+sy_font+" /Symbol findfont "+string fsize+ 432 " scalefont def\n"; 433 for(i=0;i<len font_arr;i++){ 434 (j,font)=font_arr[i]; 435 if (j==-1) break; 436 } 437 if (j==len font_arr) 438 return "Error"; 439 font_arr[i]=(bits,enc_font); 440 if (bits==1) 441 def_font=enc_font; 442 curfont++; 443 retval+= ps_func; 444 retval+= xtra_func; 445 return retval; 446} 447 448deffont() : string 449{ 450 return def_font; 451} 452 453getline(k : int, input : string) : (array of Iteminfo, string) 454{ 455 lineval,args : string; 456 j, nb : int; 457 lw:=0; 458 wid:=0; 459 flags:=0; 460 item_arr := array[32] of {* => Iteminfo(-1,-1,-1,-1,-1,-1,"")}; 461 curitem:=0; 462 while(input!=nil){ 463 (nil,input)=str->splitl(input,"["); 464 if (input==nil) 465 break; 466 com:=input[1]; 467 input=input[2:]; 468 case com { 469 'A' => 470 nb=0; 471 # get the width of the item 472 (wid,input)=str->toint(input,10); 473 wid=(wid*PTPI)/PXPI; 474 if (input[0]!='{') 475 return (nil, sys->sprint( 476 "line %d item %d Bad Syntax : '{' expected", 477 k,curitem)); 478 # get the args. 479 (args,input)=str->splitl(input,"}"); 480 # get the flags. 481 # assume there is only one int flag.. 482 (flags,args)=str->toint(args[1:],16); 483 if (args!=nil && debug){ 484 sys->print("line %d item %d extra flags=%s\n", 485 k,curitem,args); 486 } 487 if (flags<1024) flags=1; 488 item_arr[curitem].font=flags; 489 item_arr[curitem].offset=lw; 490 item_arr[curitem].width=wid; 491 lw+=wid; 492 for(j=1;j<len input;j++){ 493 if ((input[j]==')')||(input[j]=='(')) 494 lineval[len lineval]='\\'; 495 if (input[j]=='[') 496 nb++; 497 if (input[j]==']') 498 if (nb==0) 499 break; 500 else 501 nb--; 502 lineval[len lineval]=input[j]; 503 } 504 if (j<len input) 505 input=input[j:]; 506 item_arr[curitem].buf=lineval; 507 item_arr[curitem].line=k; 508 item_arr[curitem].itype=ASCII; 509 curitem++; 510 lineval=""; 511 'R' => 512 nb=0; 513 # get the width of the item 514 (wid,input)=str->toint(input,10); 515 wid=(wid*PTPI)/PXPI; 516 if (input[0]!='{') 517 return (nil, "Bad Syntax : '{' expected"); 518 # get the args. 519 (args,input)=str->splitl(input,"}"); 520 # get the flags. 521 # assume there is only one int flag.. 522 (flags,args)=str->toint(args[1:],16); 523 if (args!=nil && debug){ 524 sys->print("line %d item %d Bad Syntax args=%s", 525 k,curitem,args); 526 } 527 item_arr[curitem].font=flags; 528 item_arr[curitem].offset=lw; 529 item_arr[curitem].width=wid; 530 lw+=wid; 531 for(j=1;j<len input;j++){ 532 if (input[j]=='[') 533 nb++; 534 if (input[j]==']') 535 if (nb==0) 536 break; 537 else 538 nb--; 539 case input[j] { 540 8226 => # bullet 541 lineval+="\\267 "; 542 169 => # copyright 543 lineval+="\\251 "; 544 curitem++; 545 * => 546 lineval[len lineval]=input[j]; 547 } 548 } 549 if (j>len input) 550 input=input[j:]; 551 item_arr[curitem].buf=lineval; 552 item_arr[curitem].line=k; 553 item_arr[curitem].itype=RUNE; 554 curitem++; 555 lineval=""; 556 'N' or 'C'=> 557 # next item 558 for(j=0;j<len input;j++) 559 if (input[j]==']') 560 break; 561 if (j>len input) 562 input=input[j:]; 563 'T' => 564 (wid,input)=str->toint(input,10); 565 wid=(wid*PTPI)/PXPI; 566 item_arr[curitem].offset=lw; 567 item_arr[curitem].width=wid; 568 lw+=wid; 569 lineval[len lineval]='\t'; 570 # next item 571 for(j=0;j<len input;j++) 572 if (input[j]==']') 573 break; 574 if (j>len input) 575 input=input[j:]; 576 item_arr[curitem].buf=lineval; 577 item_arr[curitem].line=k; 578 item_arr[curitem].itype=ASCII; 579 curitem++; 580 lineval=""; 581 'W' => 582 (wid,input)=str->toint(input,10); 583 wid=(wid*PTPI)/PXPI; 584 item_arr[curitem].offset=lw; 585 item_arr[curitem].width=wid; 586 item_arr[curitem].itype=IMAGE; 587 lw+=wid; 588 # next item 589 for(j=1;j<len input;j++){ 590 if (input[j]==']') 591 break; 592 lineval[len lineval]=input[j]; 593 } 594 item_arr[curitem].buf=lineval; 595 if (j>len input) 596 input=input[j:]; 597 curitem++; 598 lineval=""; 599 * => 600 # next item 601 for(j=0;j<len input;j++) 602 if (input[j]==']') 603 break; 604 if (j>len input) 605 input=input[j:]; 606 607 } 608 } 609 return (item_arr[0:curitem], ""); 610} 611 612writeimage(ioutb: ref Iobuf, im: ref Draw->Image, dpi: int) 613{ 614 r := im.r; 615 width := r.dx(); 616 height := r.dy(); 617 iwidth := width * 72 / dpi; 618 iheight := height * 72 / dpi; 619 xstart := 72; 620 ystart := 720 - iheight; 621 bbox := Rect((xstart,ystart), (xstart+iwidth,ystart+iheight)); 622 preamble(ioutb, bbox); 623 ioutb.puts("%%Page: 1\n%%BeginPageSetup\n"); 624 ioutb.puts("/pgsave save def\n"); 625 ioutb.puts("%%EndPageSetup\n"); 626 bps := im.depth; 627 ioutb.puts(sys->sprint("%d 0 %d %d %d %d %d %d doimage\n", iheight, iwidth, ystart, xstart, height, width, bps)); 628 imagebits(ioutb, im); 629 ioutb.puts("pgsave restore\nshowpage\n"); 630 trailer(ioutb, 1); 631 ioutb.flush(); 632} 633 634imagebits(ioutb: ref Iobuf, im: ref Draw->Image) 635{ 636 if(debug) 637 sys->print("imagebits, r=%d %d %d %d, depth=%d\n", 638 im.r.min.x, im.r.min.y, im.r.max.x, im.r.max.y, im.depth); 639 width:=im.r.dx(); 640 height:=im.r.dy(); 641 bps:=im.depth; # bits per sample 642 spb := 1; # samples per byte 643 bitoff := 0; # bit offset of beginning sample within first byte 644 linebytes := width; 645 if(bps < 8) { 646 spb=8/bps; 647 bitoff=(im.r.min.x % spb) * bps; 648 linebytes=(bitoff + (width-1)*bps) / 8 + 1; 649 } 650 arr:=array[linebytes*height] of byte; 651 n:=im.readpixels(im.r,arr); 652 if(debug) 653 sys->print("linebytes=%d, height=%d, readpixels returned %d\n", 654 linebytes, height, n); 655 if(n < 0) { 656 n = len arr; 657 for(i := 0; i < n; i++) 658 arr[i] = byte 0; 659 } 660 if(bitoff != 0) { 661 # Postscript image wants beginning of line at beginning of byte 662 pslinebytes := (width-1)*bps + 1; 663 if(debug) 664 sys->print("bitoff=%d, pslinebytes=%d\n", bitoff, pslinebytes); 665 old:=arr; 666 n = pslinebytes*height; 667 arr=array[n] of byte; 668 a0 := 0; 669 o0 := 0; 670 for(y := 0; y < height; y++) { 671 for(i:=0; i < pslinebytes; i++) 672 arr[a0+i] = (old[o0+i]<<bitoff) | (old[o0+i+1]>>(8-bitoff)); 673 a0 += pslinebytes; 674 o0 += linebytes; 675 } 676 } 677 lsf:=0; 678 n4 := (n/4)*4; 679 for(i:=0;i<n4;i+=4){ 680 s:=cmap2ascii85(arr[i:i+4]); 681 lsf+=len s; 682 ioutb.puts(s); 683 if (lsf>74){ 684 ioutb.puts("\n"); 685 lsf=0; 686 } 687 } 688 nrest:=n-n4; 689 if(nrest!=0){ 690 foo:=array[4] of {* => byte 0}; 691 foo[0:]=arr[n4:n]; 692 s:=cmap2ascii85(foo); 693 if(s=="z") 694 s="!!!!!"; 695 ioutb.puts(s[0:nrest+1]); 696 } 697 ioutb.puts("~>\n"); 698 ioutb.flush(); 699} 700 701 702cmap2ascii85(arr : array of byte) : string 703{ 704 b := array[4] of {* => big 0}; 705 for(i:=0;i<4;i++) 706 b[i]=big arr[i]; 707 i1:=(b[0]<<24)+(b[1]<<16)+(b[2]<<8)+b[3]; 708 c1:=sys->sprint("%c%c%c%c%c",'!'+int ((i1/big (85*85*85*85))%big 85), 709 '!'+int ((i1/big (85*85*85))%big 85), 710 '!'+int ((i1/big (85*85))% big 85), 711 '!'+int ((i1/big 85)% big 85),'!'+int(i1% big 85)); 712 if (c1=="!!!!!") c1="z"; 713 return c1; 714} 715