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