Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1168
vEndOfPagePS(diagram_type *pDiag, BOOL bNewSection)
1169
{
1170
	vMove2NextPage(pDiag, bNewSection);
1171
} /* end of vEndOfPagePS */