xref: /plan9/sys/src/cmd/aux/antiword/postscript.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1 /*
2  * postscript.c
3  * Copyright (C) 1999-2005 A.J. van Os; Released under GNU GPL
4  *
5  * Description:
6  * Functions to deal with the PostScript format
7  *
8  *================================================================
9  * The function vImagePrologue is based on:
10  * jpeg2ps - convert JPEG compressed images to PostScript Level 2
11  * Copyright (C) 1994-99 Thomas Merz (tm@muc.de)
12  *================================================================
13  * The credit should go to him, but all the bugs are mine.
14  */
15 
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <string.h>
20 #include "version.h"
21 #include "antiword.h"
22 
23 /* The character set */
24 static encoding_type	eEncoding = encoding_neutral;
25 /* The image level */
26 static image_level_enum	eImageLevel = level_default;
27 /* The output must use landscape orientation */
28 static BOOL		bUseLandscape = FALSE;
29 /* The height and width of a PostScript page (in DrawUnits) */
30 static long		lPageHeight = LONG_MAX;
31 static long		lPageWidth = LONG_MAX;
32 /* The height of the footer on the current page (in DrawUnits) */
33 static long		lFooterHeight = 0;
34 /* Inside a footer (to prevent an infinite loop when the footer is too big) */
35 static BOOL		bInFtrSpace = FALSE;
36 /* Current time for a PS header */
37 static const char	*szCreationDate = NULL;
38 /* Current creator for a PS header */
39 static const char	*szCreator = NULL;
40 /* Current font information */
41 static drawfile_fontref	tFontRefCurr = (drawfile_fontref)-1;
42 static USHORT		usFontSizeCurr = 0;
43 static int		iFontColorCurr = -1;
44 /* Current vertical position information */
45 static long		lYtopCurr = -1;
46 /* PostScript page counter */
47 static int		iPageCount = 0;
48 /* Image counter */
49 static int		iImageCount = 0;
50 /* Section index */
51 static int		iSectionIndex = 0;
52 /* Are we on the first page of the section? */
53 static BOOL		bFirstInSection = TRUE;
54 
55 static void		vMoveTo(diagram_type *, long);
56 
57 static const char *iso_8859_1_data[] = {
58 "/newcodes	% ISO-8859-1 character encodings",
59 "[",
60 "140/ellipsis 141/trademark 142/perthousand 143/bullet",
61 "144/quoteleft 145/quoteright 146/guilsinglleft 147/guilsinglright",
62 "148/quotedblleft 149/quotedblright 150/quotedblbase 151/endash 152/emdash",
63 "153/minus 154/OE 155/oe 156/dagger 157/daggerdbl 158/fi 159/fl",
64 "160/space 161/exclamdown 162/cent 163/sterling 164/currency",
65 "165/yen 166/brokenbar 167/section 168/dieresis 169/copyright",
66 "170/ordfeminine 171/guillemotleft 172/logicalnot 173/hyphen 174/registered",
67 "175/macron 176/degree 177/plusminus 178/twosuperior 179/threesuperior",
68 "180/acute 181/mu 182/paragraph 183/periodcentered 184/cedilla",
69 "185/onesuperior 186/ordmasculine 187/guillemotright 188/onequarter",
70 "189/onehalf 190/threequarters 191/questiondown 192/Agrave 193/Aacute",
71 "194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198/AE 199/Ccedilla",
72 "200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204/Igrave 205/Iacute",
73 "206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve 211/Oacute",
74 "212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash",
75 "217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn",
76 "223/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde",
77 "228/adieresis 229/aring 230/ae 231/ccedilla 232/egrave 233/eacute",
78 "234/ecircumflex 235/edieresis 236/igrave 237/iacute 238/icircumflex",
79 "239/idieresis 240/eth 241/ntilde 242/ograve 243/oacute 244/ocircumflex",
80 "245/otilde 246/odieresis 247/divide 248/oslash 249/ugrave 250/uacute",
81 "251/ucircumflex 252/udieresis 253/yacute 254/thorn 255/ydieresis",
82 "] bind def",
83 "",
84 "/reencdict 12 dict def",
85 "",
86 };
87 
88 static const char *iso_8859_2_data[] = {
89 "/newcodes	% ISO-8859-2 character encodings",
90 "[",
91 "160/space 161/Aogonek 162/breve 163/Lslash 164/currency 165/Lcaron",
92 "166/Sacute 167/section 168/dieresis 169/Scaron 170/Scommaaccent",
93 "171/Tcaron 172/Zacute 173/hyphen 174/Zcaron 175/Zdotaccent 176/degree",
94 "177/aogonek 178/ogonek 179/lslash 180/acute 181/lcaron 182/sacute",
95 "183/caron 184/cedilla 185/scaron 186/scommaaccent 187/tcaron",
96 "188/zacute 189/hungarumlaut 190/zcaron 191/zdotaccent 192/Racute",
97 "193/Aacute 194/Acircumflex 195/Abreve 196/Adieresis 197/Lacute",
98 "198/Cacute 199/Ccedilla 200/Ccaron 201/Eacute 202/Eogonek",
99 "203/Edieresis 204/Ecaron 205/Iacute 206/Icircumflex 207/Dcaron",
100 "208/Dcroat 209/Nacute 210/Ncaron 211/Oacute 212/Ocircumflex",
101 "213/Ohungarumlaut 214/Odieresis 215/multiply 216/Rcaron 217/Uring",
102 "218/Uacute 219/Uhungarumlaut 220/Udieresis 221/Yacute 222/Tcommaaccent",
103 "223/germandbls 224/racute 225/aacute 226/acircumflex 227/abreve",
104 "228/adieresis 229/lacute 230/cacute 231/ccedilla 232/ccaron 233/eacute",
105 "234/eogonek 235/edieresis 236/ecaron 237/iacute 238/icircumflex",
106 "239/dcaron 240/dcroat 241/nacute 242/ncaron 243/oacute 244/ocircumflex",
107 "245/ohungarumlaut 246/odieresis 247/divide 248/rcaron 249/uring",
108 "250/uacute 251/uhungarumlaut 252/udieresis 253/yacute 254/tcommaaccent",
109 "255/dotaccent",
110 "] bind def",
111 "",
112 "/reencdict 12 dict def",
113 "",
114 };
115 
116 static const char *iso_8859_5_data[] = {
117 "/newcodes	% ISO-8859-5 character encodings",
118 "[",
119 "160/space     161/afii10023 162/afii10051 163/afii10052 164/afii10053",
120 "165/afii10054 166/afii10055 167/afii10056 168/afii10057 169/afii10058",
121 "170/afii10059 171/afii10060 172/afii10061 173/hyphen    174/afii10062",
122 "175/afii10145 176/afii10017 177/afii10018 178/afii10019 179/afii10020",
123 "180/afii10021 181/afii10022 182/afii10024 183/afii10025 184/afii10026",
124 "185/afii10027 186/afii10028 187/afii10029 188/afii10030 189/afii10031",
125 "190/afii10032 191/afii10033 192/afii10034 193/afii10035 194/afii10036",
126 "195/afii10037 196/afii10038 197/afii10039 198/afii10040 199/afii10041",
127 "200/afii10042 201/afii10043 202/afii10044 203/afii10045 204/afii10046",
128 "205/afii10047 206/afii10048 207/afii10049 208/afii10065 209/afii10066",
129 "210/afii10067 211/afii10068 212/afii10069 213/afii10070 214/afii10072",
130 "215/afii10073 216/afii10074 217/afii10075 218/afii10076 219/afii10077",
131 "220/afii10078 221/afii10079 222/afii10080 223/afii10081 224/afii10082",
132 "225/afii10083 226/afii10084 227/afii10085 228/afii10086 229/afii10087",
133 "230/afii10088 231/afii10089 232/afii10090 233/afii10091 234/afii10092",
134 "235/afii10093 236/afii10094 237/afii10095 238/afii10096 239/afii10097",
135 "240/afii61352 241/afii10071 242/afii10099 243/afii10100 244/afii10101",
136 "245/afii10102 246/afii10103 247/afii10104 248/afii10105 249/afii10106",
137 "250/afii10107 251/afii10108 252/afii10109 253/section   254/afii10110",
138 "255/afii10193",
139 "] bind def",
140 "",
141 "/reencdict 12 dict def",
142 "",
143 };
144 
145 static const char *iso_8859_x_func[] = {
146 "% change fonts using ISO-8859-x characters",
147 "/ChgFnt		% size psname natname => font",
148 "{",
149 "	dup FontDirectory exch known		% is re-encoded name known?",
150 "	{ exch pop }				% yes, get rid of long name",
151 "	{ dup 3 1 roll ReEncode } ifelse	% no, re-encode it",
152 "	findfont exch scalefont setfont",
153 "} bind def",
154 "",
155 "/ReEncode",
156 "{",
157 "reencdict begin",
158 "	/newname exch def",
159 "	/basename exch def",
160 "	/basedict basename findfont def",
161 "	/newfont basedict maxlength dict def",
162 "	basedict",
163 "	{ exch dup /FID ne",
164 "		{ dup /Encoding eq",
165 "			{ exch dup length array copy newfont 3 1 roll put }",
166 "			{ exch newfont 3 1 roll put } ifelse",
167 "		}",
168 "		{ pop pop } ifelse",
169 "	} forall",
170 "	newfont /FontName newname put",
171 "	newcodes aload pop newcodes length 2 idiv",
172 "	{ newfont /Encoding get 3 1 roll put } repeat",
173 "	newname newfont definefont pop",
174 "end",
175 "} bind def",
176 "",
177 };
178 
179 static const char *misc_func[] = {
180 "% draw a line and show the string",
181 "/LineShow	% string linewidth movement",
182 "{",
183 "	gsave",
184 "		0 exch rmoveto",
185 "		setlinewidth",
186 "		dup",
187 "		stringwidth pop",
188 "		0 rlineto stroke",
189 "	grestore",
190 "	show",
191 "} bind def",
192 "",
193 "% begin an EPS file (level 2 and up)",
194 "/BeginEPSF",
195 "{",
196 "	/b4_Inc_state save def",
197 "	/dict_count countdictstack def",
198 "	/op_count count 1 sub def",
199 "	userdict begin",
200 "		/showpage { } def",
201 "		0 setgray 0 setlinecap",
202 "		1 setlinewidth 0 setlinejoin",
203 "		10 setmiterlimit [ ] 0 setdash newpath",
204 "		false setstrokeadjust false setoverprint",
205 "} bind def",
206 "",
207 "% end an EPS file",
208 "/EndEPSF {",
209 "	count op_count sub { pop } repeat",
210 "	countdictstack dict_count sub { end } repeat",
211 "	b4_Inc_state restore",
212 "} bind def",
213 "",
214 };
215 
216 
217 /*
218  * vAddPageSetup - add the page setup
219  */
220 static void
vAddPageSetup(FILE * pOutFile)221 vAddPageSetup(FILE *pOutFile)
222 {
223 	if (bUseLandscape) {
224 		fprintf(pOutFile, "%%%%BeginPageSetup\n");
225 		fprintf(pOutFile, "90 rotate\n");
226 		fprintf(pOutFile, "0.00 %.2f translate\n",
227 					-dDrawUnits2Points(lPageHeight));
228 		fprintf(pOutFile, "%%%%EndPageSetup\n");
229 	}
230 } /* end of vAddPageSetup */
231 
232 /*
233  * vAddHdrFtr - add a header or footer
234  */
235 static void
vAddHdrFtr(diagram_type * pDiag,const hdrftr_block_type * pHdrFtrInfo)236 vAddHdrFtr(diagram_type *pDiag, const hdrftr_block_type *pHdrFtrInfo)
237 {
238 	output_type	*pStart, *pPrev, *pNext;
239 
240 	fail(pDiag == NULL);
241 	fail(pHdrFtrInfo == NULL);
242 
243 	vStartOfParagraphPS(pDiag, 0);
244 	pStart = pHdrFtrInfo->pText;
245 	while (pStart != NULL) {
246 		pNext = pStart;
247 		while (pNext != NULL &&
248 		       (pNext->tNextFree != 1 ||
249 		        (pNext->szStorage[0] != PAR_END &&
250 		         pNext->szStorage[0] != HARD_RETURN))) {
251 			pNext = pNext->pNext;
252 		}
253 		if (pNext == NULL) {
254 			if (bOutputContainsText(pStart)) {
255 				vAlign2Window(pDiag, pStart,
256 					lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
257 					ALIGNMENT_LEFT);
258 			} else {
259 				vMove2NextLinePS(pDiag, pStart->usFontSize);
260 			}
261 			break;
262 		}
263 		fail(pNext->tNextFree != 1);
264 		fail(pNext->szStorage[0] != PAR_END &&
265 			pNext->szStorage[0] != HARD_RETURN);
266 
267 		if (pStart != pNext) {
268 			/* There is something to print */
269 			pPrev = pNext->pPrev;
270 			fail(pPrev->pNext != pNext);
271 			/* Cut the chain */
272 			pPrev->pNext = NULL;
273 			if (bOutputContainsText(pStart)) {
274 				/* Print it */
275 				vAlign2Window(pDiag, pStart,
276 					lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
277 					ALIGNMENT_LEFT);
278 			} else {
279 				/* Just an empty line */
280 				vMove2NextLinePS(pDiag, pStart->usFontSize);
281 			}
282 			/* Repair the chain */
283 			pPrev->pNext = pNext;
284 		}
285 		if (pNext->szStorage[0] == PAR_END) {
286 			vEndOfParagraphPS(pDiag, pNext->usFontSize,
287 					(long)pNext->usFontSize * 200);
288 		}
289 		pStart = pNext->pNext;
290 	}
291 } /* end of vAddHdrFtr */
292 
293 /*
294  * vAddHeader - add a page header
295  */
296 static void
vAddHeader(diagram_type * pDiag)297 vAddHeader(diagram_type *pDiag)
298 {
299 	const hdrftr_block_type	*pHdrInfo;
300 	const hdrftr_block_type	*pFtrInfo;
301 
302 	fail(pDiag == NULL);
303 
304 	NO_DBG_MSG("vAddHeader");
305 
306 	pHdrInfo = pGetHdrFtrInfo(iSectionIndex, TRUE,
307 					odd(iPageCount), bFirstInSection);
308 	pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
309 					odd(iPageCount), bFirstInSection);
310 	/* Set the height of the footer of this page */
311 	lFooterHeight = pFtrInfo == NULL ? 0 : pFtrInfo->lHeight;
312 	fail(lFooterHeight < 0);
313 
314 	if (pHdrInfo == NULL ||
315 	    pHdrInfo->pText == NULL ||
316 	    pHdrInfo->lHeight <= 0) {
317 		fail(pHdrInfo != NULL && pHdrInfo->lHeight < 0);
318 		fail(pHdrInfo != NULL &&
319 			pHdrInfo->pText != NULL &&
320 			pHdrInfo->lHeight == 0);
321 		return;
322 	}
323 
324 	vAddHdrFtr(pDiag, pHdrInfo);
325 
326 	DBG_DEC_C(pHdrInfo->lHeight !=
327 		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
328 		pHdrInfo->lHeight);
329 	DBG_DEC_C(pHdrInfo->lHeight !=
330 		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
331 		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop);
332 
333 #if 0 /* defined(DEBUG) */
334 	fprintf(pDiag->pOutFile,
335 	"(HEADER: FileOffset 0x%04lx-0x%04lx; Height %ld-%ld) show\n",
336 		ulCharPos2FileOffset(pHdrInfo->ulCharPosStart),
337 		ulCharPos2FileOffset(pHdrInfo->ulCharPosNext),
338 		pHdrInfo->lHeight,
339 		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop);
340 #endif
341 } /* end of vAddHeader */
342 
343 /*
344  * vAddFooter - add a page footer
345  */
346 static void
vAddFooter(diagram_type * pDiag)347 vAddFooter(diagram_type *pDiag)
348 {
349 	const hdrftr_block_type	*pFtrInfo;
350 
351 	fail(pDiag == NULL);
352 
353 	NO_DBG_MSG("vAddFooter");
354 	pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
355 					odd(iPageCount), bFirstInSection);
356 	bFirstInSection = FALSE;
357 	if (pFtrInfo == NULL ||
358 	    pFtrInfo->pText == NULL ||
359 	    pFtrInfo->lHeight <= 0) {
360 		fail(pFtrInfo != NULL && pFtrInfo->lHeight < 0);
361 		fail(pFtrInfo != NULL &&
362 			pFtrInfo->pText != NULL &&
363 			pFtrInfo->lHeight == 0);
364 		return;
365 	}
366 
367 	bInFtrSpace = TRUE;
368 
369 	DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, pFtrInfo->lHeight);
370 	DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, lFooterHeight);
371 	DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
372 			pDiag->lYtop);
373 	DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
374 			lFooterHeight + PS_BOTTOM_MARGIN);
375 
376 	if (pDiag->lYtop > lFooterHeight + PS_BOTTOM_MARGIN) {
377 		/* Move down to the start of the footer */
378 		pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
379 		vMoveTo(pDiag, 0);
380 	} else if (pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN / 2) {
381 		DBG_FIXME();
382 		/*
383 		 * Move up to the start of the footer, to prevent moving
384 		 * of the bottom edge of the paper
385 		 */
386 		pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
387 		vMoveTo(pDiag, 0);
388 	}
389 
390 	DBG_FLT_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
391 	dDrawUnits2Points(lFooterHeight + PS_BOTTOM_MARGIN - pDiag->lYtop));
392 
393 #if 0 /* defined(DEBUG) */
394 	fprintf(pDiag->pOutFile,
395 	"(FOOTER: FileOffset 0x%04lx-0x%04lx; Bottom %ld-%ld) show\n",
396 		ulCharPos2FileOffset(pFtrInfo->ulCharPosStart),
397 		ulCharPos2FileOffset(pFtrInfo->ulCharPosNext),
398 		pDiag->lYtop,
399 		pFtrInfo->lHeight + PS_BOTTOM_MARGIN);
400 #endif
401 	vAddHdrFtr(pDiag, pFtrInfo);
402 	bInFtrSpace = FALSE;
403 } /* end of vAddFooter */
404 
405 /*
406  * vMove2NextPage - move to the start of the next page
407  */
408 static void
vMove2NextPage(diagram_type * pDiag,BOOL bNewSection)409 vMove2NextPage(diagram_type *pDiag, BOOL bNewSection)
410 {
411 	fail(pDiag == NULL);
412 
413 	vAddFooter(pDiag);
414 	fprintf(pDiag->pOutFile, "showpage\n");
415 	iPageCount++;
416 	fprintf(pDiag->pOutFile, "%%%%Page: %d %d\n", iPageCount, iPageCount);
417 	if (bNewSection) {
418 		iSectionIndex++;
419 		bFirstInSection = TRUE;
420 	}
421 	vAddPageSetup(pDiag->pOutFile);
422 	pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
423 	lYtopCurr = -1;
424 	vAddHeader(pDiag);
425 } /* end of vMove2NextPage */
426 
427 /*
428  * vMoveTo - move to the specified X,Y coordinates
429  *
430  * Move the current position of the specified diagram to its X,Y coordinates,
431  * start on a new page if needed
432  */
433 static void
vMoveTo(diagram_type * pDiag,long lLastVerticalMovement)434 vMoveTo(diagram_type *pDiag, long lLastVerticalMovement)
435 {
436 	fail(pDiag == NULL);
437 	fail(pDiag->pOutFile == NULL);
438 
439 	if (pDiag->lYtop <= lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace) {
440 		vMove2NextPage(pDiag, FALSE);
441 		/* Repeat the last vertical movement on the new page */
442 		pDiag->lYtop -= lLastVerticalMovement;
443 	}
444 
445 	fail(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace);
446 	DBG_DEC_C(pDiag->lYtop < PS_BOTTOM_MARGIN, pDiag->lYtop);
447 	fail(pDiag->lYtop < PS_BOTTOM_MARGIN / 3);
448 
449 	if (pDiag->lYtop != lYtopCurr) {
450 		fprintf(pDiag->pOutFile, "%.2f %.2f moveto\n",
451 			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
452 			dDrawUnits2Points(pDiag->lYtop));
453 		lYtopCurr = pDiag->lYtop;
454 	}
455 } /* end of vMoveTo */
456 
457 /*
458  * vProloguePS - set options and perform the PostScript initialization
459  */
460 void
vProloguePS(diagram_type * pDiag,const char * szTask,const char * szFilename,const options_type * pOptions)461 vProloguePS(diagram_type *pDiag,
462 	const char *szTask, const char *szFilename,
463 	const options_type *pOptions)
464 {
465 	FILE	*pOutFile;
466 	const char	*szTmp;
467 	time_t	tTime;
468 
469 	fail(pDiag == NULL);
470 	fail(pDiag->pOutFile == NULL);
471 	fail(szTask == NULL || szTask[0] == '\0');
472 	fail(pOptions == NULL);
473 
474 	pOutFile = pDiag->pOutFile;
475 
476 	bUseLandscape = pOptions->bUseLandscape;
477 	eEncoding = pOptions->eEncoding;
478 	eImageLevel = pOptions->eImageLevel;
479 
480 	if (pOptions->iPageHeight == INT_MAX) {
481 		lPageHeight = LONG_MAX;
482 	} else {
483 		lPageHeight = lPoints2DrawUnits(pOptions->iPageHeight);
484 	}
485 	DBG_DEC(lPageHeight);
486 	if (pOptions->iPageWidth == INT_MAX) {
487 		lPageWidth = LONG_MAX;
488 	} else {
489 		lPageWidth = lPoints2DrawUnits(pOptions->iPageWidth);
490 	}
491 	DBG_DEC(lPageWidth);
492 	lFooterHeight = 0;
493 	bInFtrSpace = FALSE;
494 
495 	tFontRefCurr = (drawfile_fontref)-1;
496 	usFontSizeCurr = 0;
497 	iFontColorCurr = -1;
498 	lYtopCurr = -1;
499 	iPageCount = 0;
500 	iImageCount = 0;
501 	iSectionIndex = 0;
502 	bFirstInSection = TRUE;
503 	pDiag->lXleft = 0;
504 	pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
505 
506 	szCreator = szTask;
507 
508 	fprintf(pOutFile, "%%!PS-Adobe-2.0\n");
509 	fprintf(pOutFile, "%%%%Title: %s\n", szBasename(szFilename));
510 	fprintf(pOutFile, "%%%%Creator: %s %s\n", szCreator, VERSIONSTRING);
511 	szTmp = getenv("LOGNAME");
512 	if (szTmp == NULL || szTmp[0] == '\0') {
513 		szTmp = getenv("USER");
514 		if (szTmp == NULL || szTmp[0] == '\0') {
515 			szTmp = "unknown";
516 		}
517 	}
518 	fprintf(pOutFile, "%%%%For: %.50s\n", szTmp);
519 	errno = 0;
520 	tTime = time(NULL);
521 	if (tTime == (time_t)-1 && errno != 0) {
522 		szCreationDate = NULL;
523 	} else {
524 		szCreationDate = ctime(&tTime);
525 	}
526 	if (szCreationDate == NULL || szCreationDate[0] == '\0') {
527 		szCreationDate = "unknown\n";
528 	}
529 	fprintf(pOutFile, "%%%%CreationDate: %s", szCreationDate);
530 	if (bUseLandscape) {
531 		fprintf(pOutFile, "%%%%Orientation: Landscape\n");
532 		fprintf(pOutFile, "%%%%BoundingBox: 0 0 %.0f %.0f\n",
533 				dDrawUnits2Points(lPageHeight),
534 				dDrawUnits2Points(lPageWidth));
535 	} else {
536 		fprintf(pOutFile, "%%%%Orientation: Portrait\n");
537 		fprintf(pOutFile, "%%%%BoundingBox: 0 0 %.0f %.0f\n",
538 				dDrawUnits2Points(lPageWidth),
539 				dDrawUnits2Points(lPageHeight));
540 	}
541 } /* end of vProloguePS */
542 
543 /*
544  * vEpiloguePS - clean up after everything is done
545  */
546 void
vEpiloguePS(diagram_type * pDiag)547 vEpiloguePS(diagram_type *pDiag)
548 {
549 	fail(pDiag == NULL);
550 	fail(pDiag->pOutFile == NULL);
551 
552 	if (pDiag->lYtop < lPageHeight - PS_TOP_MARGIN) {
553 		vAddFooter(pDiag);
554 		fprintf(pDiag->pOutFile, "showpage\n");
555 	}
556 	fprintf(pDiag->pOutFile, "%%%%Trailer\n");
557 	fprintf(pDiag->pOutFile, "%%%%Pages: %d\n", iPageCount);
558 	fprintf(pDiag->pOutFile, "%%%%EOF\n");
559 	szCreationDate = NULL;
560 	szCreator = NULL;
561 } /* end of vEpiloguePS */
562 
563 /*
564  * vPrintPalette - print a postscript palette
565  */
566 static void
vPrintPalette(FILE * pOutFile,const imagedata_type * pImg)567 vPrintPalette(FILE *pOutFile, const imagedata_type *pImg)
568 {
569 	int	iIndex;
570 
571 	fail(pOutFile == NULL);
572 	fail(pImg == NULL);
573 	fail(pImg->iColorsUsed < 2);
574 	fail(pImg->iColorsUsed > 256);
575 
576 	fprintf(pOutFile, "[ /Indexed\n");
577 	fprintf(pOutFile, "\t/Device%s %d\n",
578 		pImg->bColorImage ? "RGB" : "Gray", pImg->iColorsUsed - 1);
579 	fprintf(pOutFile, "<");
580 	for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
581 		fprintf(pOutFile, "%02x",
582 				(unsigned int)pImg->aucPalette[iIndex][0]);
583 		if (pImg->bColorImage) {
584 			fprintf(pOutFile, "%02x%02x",
585 				(unsigned int)pImg->aucPalette[iIndex][1],
586 				(unsigned int)pImg->aucPalette[iIndex][2]);
587 		}
588 		if (iIndex % 8 == 7) {
589 			fprintf(pOutFile, "\n");
590 		} else {
591 			fprintf(pOutFile, " ");
592 		}
593 	}
594 	fprintf(pOutFile, ">\n");
595 	fprintf(pOutFile, "] setcolorspace\n");
596 } /* end of vPrintPalette */
597 
598 /*
599  * vImageProloguePS - perform the Encapsulated PostScript initialization
600  */
601 void
vImageProloguePS(diagram_type * pDiag,const imagedata_type * pImg)602 vImageProloguePS(diagram_type *pDiag, const imagedata_type *pImg)
603 {
604 	FILE	*pOutFile;
605 
606 	fail(pDiag == NULL);
607 	fail(pDiag->pOutFile == NULL);
608 	fail(pImg == NULL);
609 
610 	if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
611 		return;
612 	}
613 
614 	fail(szCreationDate == NULL);
615 	fail(szCreator == NULL);
616 	fail(eImageLevel == level_no_images);
617 
618 	iImageCount++;
619 
620 	DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
621 
622 	pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
623 	vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
624 
625 	pOutFile = pDiag->pOutFile;
626 
627 	fprintf(pOutFile, "BeginEPSF\n");
628 	fprintf(pOutFile, "%%%%BeginDocument: image%03d.eps\n", iImageCount);
629 	fprintf(pOutFile, "%%!PS-Adobe-2.0 EPSF-2.0\n");
630 	fprintf(pOutFile, "%%%%Creator: %s %s\n", szCreator, VERSIONSTRING);
631 	fprintf(pOutFile, "%%%%Title: Image %03d\n", iImageCount);
632 	fprintf(pOutFile, "%%%%CreationDate: %s", szCreationDate);
633 	fprintf(pOutFile, "%%%%BoundingBox: 0 0 %d %d\n",
634 				pImg->iHorSizeScaled, pImg->iVerSizeScaled);
635 	fprintf(pOutFile, "%%%%DocumentData: Clean7Bit\n");
636 	fprintf(pOutFile, "%%%%LanguageLevel: 2\n");
637 	fprintf(pOutFile, "%%%%EndComments\n");
638 	fprintf(pOutFile, "%%%%BeginProlog\n");
639 	fprintf(pOutFile, "%%%%EndProlog\n");
640 	fprintf(pOutFile, "%%%%Page: 1 1\n");
641 
642 	fprintf(pOutFile, "save\n");
643 
644 	switch (pImg->eImageType) {
645 	case imagetype_is_jpeg:
646 		fprintf(pOutFile, "/Data1 currentfile ");
647 		fprintf(pOutFile, "/ASCII85Decode filter def\n");
648 		fprintf(pOutFile, "/Data Data1 << ");
649 		fprintf(pOutFile, ">> /DCTDecode filter def\n");
650 		switch (pImg->iComponents) {
651 		case 1:
652 			fprintf(pOutFile, "/DeviceGray setcolorspace\n");
653 			break;
654 		case 3:
655 			fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
656 			break;
657 		case 4:
658 			fprintf(pOutFile, "/DeviceCMYK setcolorspace\n");
659 			break;
660 		default:
661 			DBG_DEC(pImg->iComponents);
662 			break;
663 		}
664 		break;
665 	case imagetype_is_png:
666 		if (eImageLevel == level_gs_special) {
667 			fprintf(pOutFile,
668 			"/Data2 currentfile /ASCII85Decode filter def\n");
669 			fprintf(pOutFile,
670 			"/Data1 Data2 << >> /FlateDecode filter def\n");
671 			fprintf(pOutFile, "/Data Data1 <<\n");
672 			fprintf(pOutFile, "\t/Colors %d\n", pImg->iComponents);
673 			fprintf(pOutFile, "\t/BitsPerComponent %u\n",
674 						pImg->uiBitsPerComponent);
675 			fprintf(pOutFile, "\t/Columns %d\n", pImg->iWidth);
676 			fprintf(pOutFile,
677 				">> /PNGPredictorDecode filter def\n");
678 		} else {
679 			fprintf(pOutFile,
680 			"/Data1 currentfile /ASCII85Decode filter def\n");
681 			fprintf(pOutFile,
682 			"/Data Data1 << >> /FlateDecode filter def\n");
683 		}
684 		if (pImg->iComponents == 3 || pImg->iComponents == 4) {
685 			fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
686 		} else if (pImg->iColorsUsed > 0) {
687 			vPrintPalette(pOutFile, pImg);
688 		} else {
689 			fprintf(pOutFile, "/DeviceGray setcolorspace\n");
690 		}
691 		break;
692 	case imagetype_is_dib:
693 		fprintf(pOutFile, "/Data currentfile ");
694 		fprintf(pOutFile, "/ASCII85Decode filter def\n");
695 		if (pImg->uiBitsPerComponent <= 8) {
696 			vPrintPalette(pOutFile, pImg);
697 		} else {
698 			fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
699 		}
700 		break;
701 	default:
702 		fprintf(pOutFile, "/Data currentfile ");
703 		fprintf(pOutFile, "/ASCIIHexDecode filter def\n");
704 		fprintf(pOutFile, "/Device%s setcolorspace\n",
705 			pImg->bColorImage ? "RGB" : "Gray");
706 		break;
707 	}
708 
709 	/* Translate to lower left corner of image */
710 	fprintf(pOutFile, "%.2f %.2f translate\n",
711 			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
712 			dDrawUnits2Points(pDiag->lYtop));
713 
714 	fprintf(pOutFile, "%d %d scale\n",
715 				pImg->iHorSizeScaled, pImg->iVerSizeScaled);
716 
717 	fprintf(pOutFile, "{ <<\n");
718 	fprintf(pOutFile, "\t/ImageType 1\n");
719 	fprintf(pOutFile, "\t/Width %d\n", pImg->iWidth);
720 	fprintf(pOutFile, "\t/Height %d\n", pImg->iHeight);
721 	if (pImg->eImageType == imagetype_is_dib) {
722 		/* Scanning from left to right and bottom to top */
723 		fprintf(pOutFile, "\t/ImageMatrix [ %d 0 0 %d 0 0 ]\n",
724 			pImg->iWidth, pImg->iHeight);
725 	} else {
726 		/* Scanning from left to right and top to bottom */
727 		fprintf(pOutFile, "\t/ImageMatrix [ %d 0 0 %d 0 %d ]\n",
728 			pImg->iWidth, -pImg->iHeight, pImg->iHeight);
729 	}
730 	fprintf(pOutFile, "\t/DataSource Data\n");
731 
732 	switch (pImg->eImageType) {
733 	case imagetype_is_jpeg:
734 		fprintf(pOutFile, "\t/BitsPerComponent 8\n");
735 		switch (pImg->iComponents) {
736 		case 1:
737 			fprintf(pOutFile, "\t/Decode [0 1]\n");
738 			break;
739 		case 3:
740 			fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
741 			break;
742 		case 4:
743 			if (pImg->bAdobe) {
744 				/*
745 				 * Adobe-conforming CMYK file
746 				 * applying workaround for color inversion
747 				 */
748 				fprintf(pOutFile,
749 					"\t/Decode [1 0 1 0 1 0 1 0]\n");
750 			} else {
751 				fprintf(pOutFile,
752 					"\t/Decode [0 1 0 1 0 1 0 1]\n");
753 			}
754 			break;
755 		default:
756 			DBG_DEC(pImg->iComponents);
757 			break;
758 		}
759 		break;
760 	case imagetype_is_png:
761 		if (pImg->iComponents == 3) {
762 			fprintf(pOutFile, "\t/BitsPerComponent 8\n");
763 			fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
764 		} else if (pImg->iColorsUsed > 0) {
765 			fail(pImg->uiBitsPerComponent > 8);
766 			fprintf(pOutFile, "\t/BitsPerComponent %u\n",
767 					pImg->uiBitsPerComponent);
768 			fprintf(pOutFile, "\t/Decode [0 %d]\n",
769 					(1 << pImg->uiBitsPerComponent) - 1);
770 		} else {
771 			fprintf(pOutFile, "\t/BitsPerComponent 8\n");
772 			fprintf(pOutFile, "\t/Decode [0 1]\n");
773 		}
774 		break;
775 	case imagetype_is_dib:
776 		fprintf(pOutFile, "\t/BitsPerComponent 8\n");
777 		if (pImg->uiBitsPerComponent <= 8) {
778 			fprintf(pOutFile, "\t/Decode [0 255]\n");
779 		} else {
780 			fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
781 		}
782 		break;
783 	default:
784 		fprintf(pOutFile, "\t/BitsPerComponent 8\n");
785 		if (pImg->bColorImage) {
786 			fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
787 		} else {
788 			fprintf(pOutFile, "\t/Decode [0 1]\n");
789 		}
790 		break;
791 	}
792 
793 	fprintf(pOutFile, "  >> image\n");
794 	fprintf(pOutFile, "  Data closefile\n");
795 	fprintf(pOutFile, "  showpage\n");
796 	fprintf(pOutFile, "  restore\n");
797 	fprintf(pOutFile, "} exec\n");
798 } /* end of vImageProloguePS */
799 
800 /*
801  * vImageEpiloguePS - clean up after Encapsulated PostScript
802  */
803 void
vImageEpiloguePS(diagram_type * pDiag)804 vImageEpiloguePS(diagram_type *pDiag)
805 {
806 	FILE	*pOutFile;
807 
808 	fail(pDiag == NULL);
809 	fail(pDiag->pOutFile == NULL);
810 
811 	pOutFile = pDiag->pOutFile;
812 
813 	fprintf(pOutFile, "%%%%EOF\n");
814 	fprintf(pOutFile, "%%%%EndDocument\n");
815 	fprintf(pOutFile, "EndEPSF\n");
816 
817 	pDiag->lXleft = 0;
818 } /* end of vImageEpiloguePS */
819 
820 /*
821  * bAddDummyImagePS - add a dummy image
822  *
823  * return TRUE when successful, otherwise FALSE
824  */
825 BOOL
bAddDummyImagePS(diagram_type * pDiag,const imagedata_type * pImg)826 bAddDummyImagePS(diagram_type *pDiag, const imagedata_type *pImg)
827 {
828 	FILE	*pOutFile;
829 
830 	fail(pDiag == NULL);
831 	fail(pDiag->pOutFile == NULL);
832 	fail(pImg == NULL);
833 
834 	if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
835 		return FALSE;
836 	}
837 
838 	iImageCount++;
839 
840 	DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
841 
842 	pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
843 	vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
844 
845 	pOutFile = pDiag->pOutFile;
846 
847 	fprintf(pOutFile, "gsave %% Image %03d\n", iImageCount);
848 	fprintf(pOutFile, "\tnewpath\n");
849 	fprintf(pOutFile, "\t%.2f %.2f moveto\n",
850 			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
851 			dDrawUnits2Points(pDiag->lYtop));
852 	fprintf(pOutFile, "\t1.0 setlinewidth\n");
853 	fprintf(pOutFile, "\t0.3 setgray\n");
854 	fprintf(pOutFile, "\t0 %d rlineto\n", pImg->iVerSizeScaled);
855 	fprintf(pOutFile, "\t%d 0 rlineto\n", pImg->iHorSizeScaled);
856 	fprintf(pOutFile, "\t0 %d rlineto\n", -pImg->iVerSizeScaled);
857 	fprintf(pOutFile, "\tclosepath\n");
858 	fprintf(pOutFile, "\tstroke\n");
859 	fprintf(pOutFile, "grestore\n");
860 
861 	pDiag->lXleft = 0;
862 
863 	return TRUE;
864 } /* end of bAddDummyImagePS */
865 
866 /*
867  * vAddFontsPS - add the list of fonts and complete the prologue
868  */
869 void
vAddFontsPS(diagram_type * pDiag)870 vAddFontsPS(diagram_type *pDiag)
871 {
872 	FILE	*pOutFile;
873 	const font_table_type *pTmp, *pTmp2;
874 	size_t	tIndex;
875 	int	iLineLen, iOurFontnameLen;
876 	BOOL	bFound;
877 
878 	fail(pDiag == NULL);
879 	fail(pDiag->pOutFile == NULL);
880 
881 	pOutFile = pDiag->pOutFile;
882 	iLineLen = fprintf(pOutFile, "%%%%DocumentFonts:");
883 
884 	if (tGetFontTableLength() == 0) {
885 		iLineLen += fprintf(pOutFile, " Courier");
886 	} else {
887 		pTmp = NULL;
888 		while ((pTmp = pGetNextFontTableRecord(pTmp)) != NULL) {
889 			/* Print the document fonts */
890 			bFound = FALSE;
891 			pTmp2 = NULL;
892 			while ((pTmp2 = pGetNextFontTableRecord(pTmp2))
893 					!= NULL && pTmp2 < pTmp) {
894 				bFound = STREQ(pTmp2->szOurFontname,
895 						pTmp->szOurFontname);
896 				if (bFound) {
897 					break;
898 				}
899 			}
900 			iOurFontnameLen = (int)strlen(pTmp->szOurFontname);
901 			if (bFound || iOurFontnameLen <= 0) {
902 				continue;
903 			}
904 			if (iLineLen + iOurFontnameLen > 76) {
905 				fprintf(pOutFile, "\n%%%%+");
906 				iLineLen = 3;
907 			}
908 			iLineLen += fprintf(pOutFile,
909 					" %s", pTmp->szOurFontname);
910 		}
911 	}
912 	fprintf(pOutFile, "\n");
913 	fprintf(pOutFile, "%%%%Pages: (atend)\n");
914 	fprintf(pOutFile, "%%%%EndComments\n");
915 	fprintf(pOutFile, "%%%%BeginProlog\n");
916 
917 	switch (eEncoding) {
918 	case encoding_latin_1:
919 		for (tIndex = 0;
920 		     tIndex < elementsof(iso_8859_1_data);
921 		     tIndex++) {
922 			fprintf(pOutFile, "%s\n", iso_8859_1_data[tIndex]);
923 		}
924 		fprintf(pOutFile, "\n");
925 		for (tIndex = 0;
926 		     tIndex < elementsof(iso_8859_x_func);
927 		     tIndex++) {
928 			fprintf(pOutFile, "%s\n", iso_8859_x_func[tIndex]);
929 		}
930 		break;
931 	case encoding_latin_2:
932 		for (tIndex = 0;
933 		     tIndex < elementsof(iso_8859_2_data);
934 		     tIndex++) {
935 			fprintf(pOutFile, "%s\n", iso_8859_2_data[tIndex]);
936 		}
937 		fprintf(pOutFile, "\n");
938 		for (tIndex = 0;
939 		     tIndex < elementsof(iso_8859_x_func);
940 		     tIndex++) {
941 			fprintf(pOutFile, "%s\n", iso_8859_x_func[tIndex]);
942 		}
943 		break;
944 	case encoding_cyrillic:
945 		for (tIndex = 0;
946 		     tIndex < elementsof(iso_8859_5_data);
947 		     tIndex++) {
948 			fprintf(pOutFile, "%s\n", iso_8859_5_data[tIndex]);
949 		}
950 		fprintf(pOutFile, "\n");
951 		for (tIndex = 0;
952 		     tIndex < elementsof(iso_8859_x_func);
953 		     tIndex++) {
954 			fprintf(pOutFile, "%s\n", iso_8859_x_func[tIndex]);
955 		}
956 		break;
957 	case encoding_utf_8:
958 		werr(1,
959 		"The combination PostScript and UTF-8 is not supported");
960 		break;
961 	default:
962 		DBG_DEC(eEncoding);
963 		break;
964 	}
965 
966 	/* The rest of the functions */
967 	for (tIndex = 0; tIndex < elementsof(misc_func); tIndex++) {
968 		fprintf(pOutFile, "%s\n", misc_func[tIndex]);
969 	}
970 	fprintf(pOutFile, "%%%%EndProlog\n");
971 	iPageCount = 1;
972 	fprintf(pDiag->pOutFile, "%%%%Page: %d %d\n", iPageCount, iPageCount);
973 	vAddPageSetup(pDiag->pOutFile);
974 	vAddHeader(pDiag);
975 } /* end of vAddFontsPS */
976 
977 /*
978  * vPrintPS - print a PostScript string
979  */
980 static void
vPrintPS(FILE * pFile,const char * szString,size_t tStringLength,USHORT usFontstyle)981 vPrintPS(FILE *pFile, const char *szString, size_t tStringLength,
982 		USHORT usFontstyle)
983 {
984 	double		dSuperscriptMove, dSubscriptMove;
985 	const UCHAR	*ucBytes;
986 	size_t		tCount;
987 
988 	fail(szString == NULL);
989 
990 	if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
991 		return;
992 	}
993 	DBG_DEC_C(usFontSizeCurr < MIN_FONT_SIZE, usFontSizeCurr);
994 
995 	dSuperscriptMove = 0.0;
996 	dSubscriptMove = 0.0;
997 
998 	/* Up for superscript */
999 	if (bIsSuperscript(usFontstyle) && usFontSizeCurr != 0) {
1000 		dSuperscriptMove = (double)((usFontSizeCurr + 1) / 2) * 0.375;
1001 		fprintf(pFile, "0 %.2f rmoveto\n", dSuperscriptMove);
1002 	}
1003 
1004 	/* Down for subscript */
1005 	if (bIsSubscript(usFontstyle) && usFontSizeCurr != 0) {
1006 		dSubscriptMove = (double)usFontSizeCurr * 0.125;
1007 		fprintf(pFile, "0 %.2f rmoveto\n", -dSubscriptMove);
1008 	}
1009 
1010 	/* Generate and print the PostScript output */
1011 	ucBytes = (UCHAR *)szString;
1012 	(void)putc('(', pFile);
1013 	for (tCount = 0; tCount < tStringLength ; tCount++) {
1014 		switch (ucBytes[tCount]) {
1015 		case '(':
1016 		case ')':
1017 		case '\\':
1018 			(void)putc('\\', pFile);
1019 			(void)putc(szString[tCount], pFile);
1020 			break;
1021 		default:
1022 			if (ucBytes[tCount] < 0x20 ||
1023 			    (ucBytes[tCount] >= 0x7f &&
1024 			     ucBytes[tCount] < 0x8c)) {
1025 				DBG_HEX(ucBytes[tCount]);
1026 				(void)putc(' ', pFile);
1027 			} else if (ucBytes[tCount] >= 0x80) {
1028 				fprintf(pFile, "\\%03o", (UINT)ucBytes[tCount]);
1029 			} else {
1030 				(void)putc(szString[tCount], pFile);
1031 			}
1032 			break;
1033 		}
1034 	}
1035 	fprintf(pFile, ") ");
1036 	if ((bIsStrike(usFontstyle) || bIsMarkDel(usFontstyle)) &&
1037 			usFontSizeCurr != 0) {
1038 		fprintf(pFile, "%.2f %.2f LineShow\n",
1039 			(double)usFontSizeCurr * 0.02,
1040 			(double)usFontSizeCurr * 0.12);
1041 	} else if (bIsUnderline(usFontstyle) && usFontSizeCurr != 0) {
1042 		fprintf(pFile, "%.2f %.2f LineShow\n",
1043 			(double)usFontSizeCurr * 0.02,
1044 			(double)usFontSizeCurr * -0.06);
1045 	} else {
1046 		fprintf(pFile, "show\n");
1047 	}
1048 
1049 	/* Undo the superscript move */
1050 	if (bIsSuperscript(usFontstyle) && usFontSizeCurr != 0) {
1051 		fprintf(pFile, "0 %.2f rmoveto\n", -dSuperscriptMove);
1052 	}
1053 
1054 	/* Undo the subscript move */
1055 	if (bIsSubscript(usFontstyle) && usFontSizeCurr != 0) {
1056 		fprintf(pFile, "0 %.2f rmoveto\n", dSubscriptMove);
1057 	}
1058 } /* end of vPrintPS */
1059 
1060 /*
1061  * vSetColor - move to the specified color
1062  */
1063 static void
vSetColor(FILE * pFile,UCHAR ucFontColor)1064 vSetColor(FILE *pFile, UCHAR ucFontColor)
1065 {
1066 	ULONG	ulTmp, ulRed, ulGreen, ulBlue;
1067 
1068 	ulTmp = ulColor2Color(ucFontColor);
1069 	ulRed   = (ulTmp & 0x0000ff00) >> 8;
1070 	ulGreen = (ulTmp & 0x00ff0000) >> 16;
1071 	ulBlue  = (ulTmp & 0xff000000) >> 24;
1072 	fprintf(pFile, "%.3f %.3f %.3f setrgbcolor\n",
1073 				ulRed / 255.0, ulGreen / 255.0, ulBlue / 255.0);
1074 } /* end of vSetColor */
1075 
1076 /*
1077  * vMove2NextLinePS - move to the next line
1078  */
1079 void
vMove2NextLinePS(diagram_type * pDiag,USHORT usFontSize)1080 vMove2NextLinePS(diagram_type *pDiag, USHORT usFontSize)
1081 {
1082 	fail(pDiag == NULL);
1083 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1084 
1085 	pDiag->lYtop -= lComputeLeading(usFontSize);
1086 } /* end of vMove2NextLinePS */
1087 
1088 /*
1089  * vSubstringPS - print a sub string
1090  */
1091 void
vSubstringPS(diagram_type * pDiag,char * szString,size_t tStringLength,long lStringWidth,UCHAR ucFontColor,USHORT usFontstyle,drawfile_fontref tFontRef,USHORT usFontSize,USHORT usMaxFontSize)1092 vSubstringPS(diagram_type *pDiag,
1093 	char *szString, size_t tStringLength, long lStringWidth,
1094 	UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
1095 	USHORT usFontSize, USHORT usMaxFontSize)
1096 {
1097 	const char	*szOurFontname;
1098 
1099 	fail(pDiag == NULL || szString == NULL);
1100 	fail(pDiag->pOutFile == NULL);
1101 	fail(pDiag->lXleft < 0);
1102 	fail(tStringLength != strlen(szString));
1103 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1104 	fail(usMaxFontSize < MIN_FONT_SIZE || usMaxFontSize > MAX_FONT_SIZE);
1105 	fail(usFontSize > usMaxFontSize);
1106 
1107 	if (szString[0] == '\0' || tStringLength == 0) {
1108 		return;
1109 	}
1110 
1111 	if (tFontRef != tFontRefCurr || usFontSize != usFontSizeCurr) {
1112 		szOurFontname = szGetFontname(tFontRef);
1113 		fail(szOurFontname == NULL);
1114 		fprintf(pDiag->pOutFile,
1115 			"%.1f /%s /%s-ISO-8859-x ChgFnt\n",
1116 			(double)usFontSize / 2.0,
1117 			szOurFontname, szOurFontname);
1118 		tFontRefCurr = tFontRef;
1119 		usFontSizeCurr = usFontSize;
1120 	}
1121 	if ((int)ucFontColor != iFontColorCurr) {
1122 		vSetColor(pDiag->pOutFile, ucFontColor);
1123 		iFontColorCurr = (int)ucFontColor;
1124 	}
1125 	vMoveTo(pDiag, lComputeLeading(usMaxFontSize));
1126 	vPrintPS(pDiag->pOutFile, szString, tStringLength, usFontstyle);
1127 	pDiag->lXleft += lStringWidth;
1128 } /* end of vSubstringPS */
1129 
1130 /*
1131  * Create an start of paragraph by moving the y-top mark
1132  */
1133 void
vStartOfParagraphPS(diagram_type * pDiag,long lBeforeIndentation)1134 vStartOfParagraphPS(diagram_type *pDiag, long lBeforeIndentation)
1135 {
1136 	fail(pDiag == NULL);
1137 	fail(lBeforeIndentation < 0);
1138 
1139 	pDiag->lXleft = 0;
1140 	pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
1141 } /* end of vStartOfParagraphPS */
1142 
1143 /*
1144  * Create an end of paragraph by moving the y-top mark
1145  */
1146 void
vEndOfParagraphPS(diagram_type * pDiag,USHORT usFontSize,long lAfterIndentation)1147 vEndOfParagraphPS(diagram_type *pDiag,
1148 	USHORT usFontSize, long lAfterIndentation)
1149 {
1150 	fail(pDiag == NULL);
1151 	fail(pDiag->pOutFile == NULL);
1152 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1153 	fail(lAfterIndentation < 0);
1154 
1155 	if (pDiag->lXleft > 0) {
1156 		/* To the start of the line */
1157 		vMove2NextLinePS(pDiag, usFontSize);
1158 	}
1159 
1160 	pDiag->lXleft = 0;
1161 	pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
1162 } /* end of vEndOfParagraphPS */
1163 
1164 /*
1165  * Create an end of page
1166  */
1167 void
vEndOfPagePS(diagram_type * pDiag,BOOL bNewSection)1168 vEndOfPagePS(diagram_type *pDiag, BOOL bNewSection)
1169 {
1170 	vMove2NextPage(pDiag, bNewSection);
1171 } /* end of vEndOfPagePS */
1172