xref: /plan9-contrib/sys/src/cmd/aux/antiword/pdf.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1*25b329d5SDavid du Colombier /*
2*25b329d5SDavid du Colombier  * pdf.c
3*25b329d5SDavid du Colombier  * Copyright (C) 2003-2005 A.J. van Os; Released under GNU GPL
4*25b329d5SDavid du Colombier  *
5*25b329d5SDavid du Colombier  * Description:
6*25b329d5SDavid du Colombier  * Functions to deal with the Adobe Portable Document Format (pdf)
7*25b329d5SDavid du Colombier  *
8*25b329d5SDavid du Colombier  */
9*25b329d5SDavid du Colombier 
10*25b329d5SDavid du Colombier #include <stdarg.h>
11*25b329d5SDavid du Colombier #include <string.h>
12*25b329d5SDavid du Colombier #include "version.h"
13*25b329d5SDavid du Colombier #include "antiword.h"
14*25b329d5SDavid du Colombier 
15*25b329d5SDavid du Colombier 
16*25b329d5SDavid du Colombier /* Constants for the file positions */
17*25b329d5SDavid du Colombier #define INITIAL_LOCATION_SIZE	20
18*25b329d5SDavid du Colombier #define INITIAL_PAGEOBJECT_SIZE	 5
19*25b329d5SDavid du Colombier #if defined(DEBUG)
20*25b329d5SDavid du Colombier #define EXTENSION_ARRAY_SIZE	10
21*25b329d5SDavid du Colombier #else
22*25b329d5SDavid du Colombier #define EXTENSION_ARRAY_SIZE	30
23*25b329d5SDavid du Colombier #endif /* DEBUG */
24*25b329d5SDavid du Colombier 
25*25b329d5SDavid du Colombier /* The character set */
26*25b329d5SDavid du Colombier static encoding_type	eEncoding = encoding_neutral;
27*25b329d5SDavid du Colombier /* Current creator for a PDF header */
28*25b329d5SDavid du Colombier static const char	*szProducer = NULL;
29*25b329d5SDavid du Colombier /* The height and width of a PDF page (in DrawUnits) */
30*25b329d5SDavid du Colombier static long		lPageHeight = LONG_MAX;
31*25b329d5SDavid du Colombier static long		lPageWidth = LONG_MAX;
32*25b329d5SDavid du Colombier /* The height of the footer on the current page (in DrawUnits) */
33*25b329d5SDavid du Colombier static long		lFooterHeight = 0;
34*25b329d5SDavid du Colombier /* Inside a footer (to prevent an infinite loop when the footer is too big) */
35*25b329d5SDavid du Colombier static BOOL		bInFtrSpace = FALSE;
36*25b329d5SDavid du Colombier /* Current font information */
37*25b329d5SDavid du Colombier static drawfile_fontref	tFontRefCurr = (drawfile_fontref)-1;
38*25b329d5SDavid du Colombier static USHORT		usFontSizeCurr = 0;
39*25b329d5SDavid du Colombier static int		iFontColorCurr = -1;
40*25b329d5SDavid du Colombier /* Current vertical position information */
41*25b329d5SDavid du Colombier static long		lYtopCurr = -1;
42*25b329d5SDavid du Colombier /* Image counter */
43*25b329d5SDavid du Colombier static int		iImageCount = 0;
44*25b329d5SDavid du Colombier /* Section index */
45*25b329d5SDavid du Colombier static int		iSectionIndex = 0;
46*25b329d5SDavid du Colombier /* Are we on the first page of the section? */
47*25b329d5SDavid du Colombier static BOOL		bFirstInSection = TRUE;
48*25b329d5SDavid du Colombier /* File positions */
49*25b329d5SDavid du Colombier static long		lFilePosition = 0;
50*25b329d5SDavid du Colombier static long		*alLocation = NULL;
51*25b329d5SDavid du Colombier static size_t		tLocations = 0;
52*25b329d5SDavid du Colombier static int		iMaxLocationNumber = 0;
53*25b329d5SDavid du Colombier /* File position at the start of a page */
54*25b329d5SDavid du Colombier static long		lStreamStart = -1;
55*25b329d5SDavid du Colombier /* Page objects */
56*25b329d5SDavid du Colombier static int		*aiPageObject = NULL;
57*25b329d5SDavid du Colombier static int		iPageCount = 0;
58*25b329d5SDavid du Colombier static size_t		tMaxPageObjects = 0;
59*25b329d5SDavid du Colombier /* Current object number */
60*25b329d5SDavid du Colombier /* 1 = root; 2 = info; 3 = pages; 4 = encoding; 5-16 = fonts; 17 = resources */
61*25b329d5SDavid du Colombier static int		iObjectNumberCurr = 17;
62*25b329d5SDavid du Colombier 
63*25b329d5SDavid du Colombier static void		vMoveTo(diagram_type *, long);
64*25b329d5SDavid du Colombier 
65*25b329d5SDavid du Colombier static const struct {
66*25b329d5SDavid du Colombier 	const char	*szPDFname;
67*25b329d5SDavid du Colombier 	const char	*szPSname;
68*25b329d5SDavid du Colombier } atFontname[] = {
69*25b329d5SDavid du Colombier 	{ "Courier",			FONT_MONOSPACED_PLAIN },
70*25b329d5SDavid du Colombier 	{ "Courier-Bold",		FONT_MONOSPACED_BOLD },
71*25b329d5SDavid du Colombier 	{ "Courier-Oblique",		FONT_MONOSPACED_ITALIC },
72*25b329d5SDavid du Colombier 	{ "Courier-BoldOblique",	FONT_MONOSPACED_BOLDITALIC },
73*25b329d5SDavid du Colombier 	{ "Helvetica",			FONT_SANS_SERIF_PLAIN },
74*25b329d5SDavid du Colombier 	{ "Helvetica-Bold",		FONT_SANS_SERIF_BOLD },
75*25b329d5SDavid du Colombier 	{ "Helvetica-Oblique",		FONT_SANS_SERIF_ITALIC },
76*25b329d5SDavid du Colombier 	{ "Helvetica-BoldOblique",	FONT_SANS_SERIF_BOLDITALIC },
77*25b329d5SDavid du Colombier 	{ "Times-Roman",		FONT_SERIF_PLAIN },
78*25b329d5SDavid du Colombier 	{ "Times-Bold",			FONT_SERIF_BOLD },
79*25b329d5SDavid du Colombier 	{ "Times-Italic",		FONT_SERIF_ITALIC },
80*25b329d5SDavid du Colombier 	{ "Times-BoldItalic",		FONT_SERIF_BOLDITALIC },
81*25b329d5SDavid du Colombier };
82*25b329d5SDavid du Colombier 
83*25b329d5SDavid du Colombier static const char *iso_8859_1[] = {
84*25b329d5SDavid du Colombier "128 /Euro",
85*25b329d5SDavid du Colombier "140 /ellipsis /trademark /perthousand /bullet",
86*25b329d5SDavid du Colombier "    /quoteleft /quoteright /guilsinglleft /guilsinglright",
87*25b329d5SDavid du Colombier "    /quotedblleft /quotedblright /quotedblbase /endash /emdash",
88*25b329d5SDavid du Colombier "    /minus /OE /oe /dagger /daggerdbl /fi /fl",
89*25b329d5SDavid du Colombier "160 /space /exclamdown /cent /sterling /currency",
90*25b329d5SDavid du Colombier "    /yen /brokenbar /section /dieresis /copyright",
91*25b329d5SDavid du Colombier "    /ordfeminine /guillemotleft /logicalnot /hyphen /registered",
92*25b329d5SDavid du Colombier "    /macron /degree /plusminus /twosuperior /threesuperior",
93*25b329d5SDavid du Colombier "    /acute /mu /paragraph /periodcentered /cedilla",
94*25b329d5SDavid du Colombier "    /onesuperior /ordmasculine /guillemotright /onequarter",
95*25b329d5SDavid du Colombier "    /onehalf /threequarters /questiondown /Agrave /Aacute",
96*25b329d5SDavid du Colombier "    /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla",
97*25b329d5SDavid du Colombier "    /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute",
98*25b329d5SDavid du Colombier "    /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute",
99*25b329d5SDavid du Colombier "    /Ocircumflex /Otilde /Odieresis /multiply /Oslash",
100*25b329d5SDavid du Colombier "    /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn",
101*25b329d5SDavid du Colombier "    /germandbls /agrave /aacute /acircumflex /atilde",
102*25b329d5SDavid du Colombier "    /adieresis /aring /ae /ccedilla /egrave /eacute",
103*25b329d5SDavid du Colombier "    /ecircumflex /edieresis /igrave /iacute /icircumflex",
104*25b329d5SDavid du Colombier "    /idieresis /eth /ntilde /ograve /oacute /ocircumflex",
105*25b329d5SDavid du Colombier "    /otilde /odieresis /divide /oslash /ugrave /uacute",
106*25b329d5SDavid du Colombier "    /ucircumflex /udieresis /yacute /thorn /ydieresis",
107*25b329d5SDavid du Colombier };
108*25b329d5SDavid du Colombier 
109*25b329d5SDavid du Colombier static const char *iso_8859_2[] = {
110*25b329d5SDavid du Colombier "160 /space /Aogonek /breve /Lslash /currency /Lcaron",
111*25b329d5SDavid du Colombier "    /Sacute /section /dieresis /Scaron /Scommaaccent",
112*25b329d5SDavid du Colombier "    /Tcaron /Zacute /hyphen /Zcaron /Zdotaccent /degree",
113*25b329d5SDavid du Colombier "    /aogonek /ogonek /lslash /acute /lcaron /sacute",
114*25b329d5SDavid du Colombier "    /caron /cedilla /scaron /scommaaccent /tcaron",
115*25b329d5SDavid du Colombier "    /zacute /hungarumlaut /zcaron /zdotaccent /Racute",
116*25b329d5SDavid du Colombier "    /Aacute /Acircumflex /Abreve /Adieresis /Lacute",
117*25b329d5SDavid du Colombier "    /Cacute /Ccedilla /Ccaron /Eacute /Eogonek",
118*25b329d5SDavid du Colombier "    /Edieresis /Ecaron /Iacute /Icircumflex /Dcaron",
119*25b329d5SDavid du Colombier "    /.notdef /Nacute /Ncaron /Oacute /Ocircumflex",
120*25b329d5SDavid du Colombier "    /Ohungarumlaut /Odieresis /multiply /Rcaron /Uring",
121*25b329d5SDavid du Colombier "    /Uacute /Uhungarumlaut /Udieresis /Yacute /Tcommaaccent",
122*25b329d5SDavid du Colombier "    /germandbls /racute /aacute /acircumflex /abreve",
123*25b329d5SDavid du Colombier "    /adieresis /lacute /cacute /ccedilla /ccaron /eacute",
124*25b329d5SDavid du Colombier "    /eogonek /edieresis /ecaron /iacute /icircumflex",
125*25b329d5SDavid du Colombier "    /dcaron /.notdef /nacute /ncaron /oacute /ocircumflex",
126*25b329d5SDavid du Colombier "    /ohungarumlaut /odieresis /divide /rcaron /uring",
127*25b329d5SDavid du Colombier "    /uacute /uhungarumlaut /udieresis /yacute /tcommaaccent",
128*25b329d5SDavid du Colombier "    /dotaccent",
129*25b329d5SDavid du Colombier };
130*25b329d5SDavid du Colombier 
131*25b329d5SDavid du Colombier 
132*25b329d5SDavid du Colombier /*
133*25b329d5SDavid du Colombier  * tGetFontIndex - get the font index
134*25b329d5SDavid du Colombier  */
135*25b329d5SDavid du Colombier static size_t
tGetFontIndex(drawfile_fontref tFontRef)136*25b329d5SDavid du Colombier tGetFontIndex(drawfile_fontref tFontRef)
137*25b329d5SDavid du Colombier {
138*25b329d5SDavid du Colombier 	const char	*szFontname;
139*25b329d5SDavid du Colombier 	size_t		tIndex;
140*25b329d5SDavid du Colombier 
141*25b329d5SDavid du Colombier 	/* Get the font name */
142*25b329d5SDavid du Colombier 	szFontname = szGetFontname(tFontRef);
143*25b329d5SDavid du Colombier 	fail(szFontname == NULL);
144*25b329d5SDavid du Colombier 	if (szFontname == NULL) {
145*25b329d5SDavid du Colombier 		return 0;
146*25b329d5SDavid du Colombier 	}
147*25b329d5SDavid du Colombier 
148*25b329d5SDavid du Colombier 	/* Find the name in the table */
149*25b329d5SDavid du Colombier 	for (tIndex = 0; tIndex < elementsof(atFontname); tIndex++) {
150*25b329d5SDavid du Colombier 		if (STRCEQ(atFontname[tIndex].szPSname, szFontname)) {
151*25b329d5SDavid du Colombier 			return tIndex;
152*25b329d5SDavid du Colombier 		}
153*25b329d5SDavid du Colombier 	}
154*25b329d5SDavid du Colombier 	/* Not found */
155*25b329d5SDavid du Colombier 	DBG_DEC(tFontRef);
156*25b329d5SDavid du Colombier 	DBG_MSG(szFontname);
157*25b329d5SDavid du Colombier 	return 0;
158*25b329d5SDavid du Colombier } /* end of tGetFontIndex */
159*25b329d5SDavid du Colombier 
160*25b329d5SDavid du Colombier /*
161*25b329d5SDavid du Colombier  * vSetLocation - store the location of objects
162*25b329d5SDavid du Colombier  */
163*25b329d5SDavid du Colombier static void
vSetLocation(int iLocationNumber)164*25b329d5SDavid du Colombier vSetLocation(int iLocationNumber)
165*25b329d5SDavid du Colombier {
166*25b329d5SDavid du Colombier 	fail(iLocationNumber <= 0);
167*25b329d5SDavid du Colombier 
168*25b329d5SDavid du Colombier 	if ((size_t)iLocationNumber >= tLocations) {
169*25b329d5SDavid du Colombier 		/* Extend and set to zero */
170*25b329d5SDavid du Colombier 		tLocations += EXTENSION_ARRAY_SIZE;
171*25b329d5SDavid du Colombier 		alLocation = xrealloc(alLocation, tLocations * sizeof(long));
172*25b329d5SDavid du Colombier 		memset(alLocation + tLocations - EXTENSION_ARRAY_SIZE,
173*25b329d5SDavid du Colombier 			0,
174*25b329d5SDavid du Colombier 			EXTENSION_ARRAY_SIZE * sizeof(long));
175*25b329d5SDavid du Colombier 		DBG_DEC(tLocations);
176*25b329d5SDavid du Colombier 	}
177*25b329d5SDavid du Colombier 	if (iLocationNumber > iMaxLocationNumber) {
178*25b329d5SDavid du Colombier 		iMaxLocationNumber = iLocationNumber;
179*25b329d5SDavid du Colombier 	}
180*25b329d5SDavid du Colombier 
181*25b329d5SDavid du Colombier 	DBG_DEC_C((size_t)iLocationNumber >= tLocations, iLocationNumber);
182*25b329d5SDavid du Colombier 	DBG_DEC_C((size_t)iLocationNumber >= tLocations, tLocations);
183*25b329d5SDavid du Colombier 	fail((size_t)iLocationNumber >= tLocations);
184*25b329d5SDavid du Colombier 
185*25b329d5SDavid du Colombier 	alLocation[iLocationNumber] = lFilePosition;
186*25b329d5SDavid du Colombier } /* end of vSetLocation */
187*25b329d5SDavid du Colombier 
188*25b329d5SDavid du Colombier /*
189*25b329d5SDavid du Colombier  * vFillNextPageObject - fil the next page object with the current object number
190*25b329d5SDavid du Colombier  */
191*25b329d5SDavid du Colombier static void
vFillNextPageObject(void)192*25b329d5SDavid du Colombier vFillNextPageObject(void)
193*25b329d5SDavid du Colombier {
194*25b329d5SDavid du Colombier 	iPageCount++;
195*25b329d5SDavid du Colombier 	if ((size_t)iPageCount >= tMaxPageObjects) {
196*25b329d5SDavid du Colombier 		/* Extend the array */
197*25b329d5SDavid du Colombier 		tMaxPageObjects += EXTENSION_ARRAY_SIZE;
198*25b329d5SDavid du Colombier 		aiPageObject = xrealloc(aiPageObject,
199*25b329d5SDavid du Colombier 					tMaxPageObjects * sizeof(int));
200*25b329d5SDavid du Colombier 		DBG_DEC(tMaxPageObjects);
201*25b329d5SDavid du Colombier 	}
202*25b329d5SDavid du Colombier 	aiPageObject[iPageCount] = iObjectNumberCurr;
203*25b329d5SDavid du Colombier } /* end of vFillNextPageObject */
204*25b329d5SDavid du Colombier 
205*25b329d5SDavid du Colombier /*
206*25b329d5SDavid du Colombier  * vFPprintf - printf and update the fileposition
207*25b329d5SDavid du Colombier  *
208*25b329d5SDavid du Colombier  * called with arguments like fprintf(3)
209*25b329d5SDavid du Colombier  */
210*25b329d5SDavid du Colombier static void
vFPprintf(FILE * pOutFile,const char * szFormat,...)211*25b329d5SDavid du Colombier vFPprintf(FILE *pOutFile, const char *szFormat, ...)
212*25b329d5SDavid du Colombier {
213*25b329d5SDavid du Colombier 	va_list	tArg;
214*25b329d5SDavid du Colombier 
215*25b329d5SDavid du Colombier 	va_start(tArg, szFormat);
216*25b329d5SDavid du Colombier 	lFilePosition += vfprintf(pOutFile, szFormat, tArg);
217*25b329d5SDavid du Colombier 	va_end(tArg);
218*25b329d5SDavid du Colombier } /* end of vFPprintf */
219*25b329d5SDavid du Colombier 
220*25b329d5SDavid du Colombier /*
221*25b329d5SDavid du Colombier  * vCreateInfoDictionary - create the document information dictionary
222*25b329d5SDavid du Colombier  */
223*25b329d5SDavid du Colombier void
vCreateInfoDictionary(diagram_type * pDiag,int iWordVersion)224*25b329d5SDavid du Colombier vCreateInfoDictionary(diagram_type *pDiag, int iWordVersion)
225*25b329d5SDavid du Colombier {
226*25b329d5SDavid du Colombier 	FILE	*pOutFile;
227*25b329d5SDavid du Colombier 	const char	*szTitle, *szAuthor, *szSubject, *szCreator;
228*25b329d5SDavid du Colombier 	const char	*szCreationDate, *szModDate;
229*25b329d5SDavid du Colombier 
230*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
231*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
232*25b329d5SDavid du Colombier 	fail(iWordVersion < 0);
233*25b329d5SDavid du Colombier 	fail(szProducer == NULL || szProducer[0] == '\0');
234*25b329d5SDavid du Colombier 
235*25b329d5SDavid du Colombier 	szTitle = szGetTitle();
236*25b329d5SDavid du Colombier 	szAuthor = szGetAuthor();
237*25b329d5SDavid du Colombier 	szSubject = szGetSubject();
238*25b329d5SDavid du Colombier 	szCreationDate = szGetCreationDate();
239*25b329d5SDavid du Colombier 	szModDate = szGetModDate();
240*25b329d5SDavid du Colombier 
241*25b329d5SDavid du Colombier 	switch (iWordVersion) {
242*25b329d5SDavid du Colombier 	case 0: szCreator = "Word for DOS"; break;
243*25b329d5SDavid du Colombier 	case 1: szCreator = "WinWord 1.x"; break;
244*25b329d5SDavid du Colombier 	case 2: szCreator = "WinWord 2.0"; break;
245*25b329d5SDavid du Colombier 	case 4: szCreator = "MacWord 4"; break;
246*25b329d5SDavid du Colombier 	case 5: szCreator = "MacWord 5"; break;
247*25b329d5SDavid du Colombier 	case 6: szCreator = "Word 6"; break;
248*25b329d5SDavid du Colombier 	case 7: szCreator = "Word 7/95"; break;
249*25b329d5SDavid du Colombier 	case 8: szCreator = "Word 97 or later"; break;
250*25b329d5SDavid du Colombier 	default: szCreator = NULL; break;
251*25b329d5SDavid du Colombier 	}
252*25b329d5SDavid du Colombier 
253*25b329d5SDavid du Colombier 	pOutFile = pDiag->pOutFile;
254*25b329d5SDavid du Colombier 
255*25b329d5SDavid du Colombier 	vSetLocation(2);
256*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "2 0 obj\n");
257*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<<\n");
258*25b329d5SDavid du Colombier 	if (szTitle != NULL && szTitle[0] != '\0') {
259*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/Title (%s)\n", szTitle);
260*25b329d5SDavid du Colombier 	}
261*25b329d5SDavid du Colombier 	if (szAuthor != NULL && szAuthor[0] != '\0') {
262*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/Author (%s)\n", szAuthor);
263*25b329d5SDavid du Colombier 	}
264*25b329d5SDavid du Colombier 	if (szSubject != NULL && szSubject[0] != '\0') {
265*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/Subject (%s)\n", szSubject);
266*25b329d5SDavid du Colombier 	}
267*25b329d5SDavid du Colombier 	if (szCreator != NULL && szCreator[0] != '\0') {
268*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/Creator (%s)\n", szCreator);
269*25b329d5SDavid du Colombier 	}
270*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Producer (%s %s)\n", szProducer, VERSIONSTRING);
271*25b329d5SDavid du Colombier 	if (szCreationDate != NULL && szCreationDate[0] != '\0') {
272*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/CreationDate (%s)\n", szCreationDate);
273*25b329d5SDavid du Colombier 	}
274*25b329d5SDavid du Colombier 	if (szModDate != NULL && szModDate[0] != '\0') {
275*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/ModDate (%s)\n", szModDate);
276*25b329d5SDavid du Colombier 	}
277*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, ">>\n");
278*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endobj\n");
279*25b329d5SDavid du Colombier } /* end of vCreateInfoDictionary */
280*25b329d5SDavid du Colombier 
281*25b329d5SDavid du Colombier /*
282*25b329d5SDavid du Colombier  * vAddHdrFtr - add a header or footer
283*25b329d5SDavid du Colombier  */
284*25b329d5SDavid du Colombier static void
vAddHdrFtr(diagram_type * pDiag,const hdrftr_block_type * pHdrFtrInfo)285*25b329d5SDavid du Colombier vAddHdrFtr(diagram_type *pDiag, const hdrftr_block_type *pHdrFtrInfo)
286*25b329d5SDavid du Colombier {
287*25b329d5SDavid du Colombier 	output_type	*pStart, *pPrev, *pNext;
288*25b329d5SDavid du Colombier 
289*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
290*25b329d5SDavid du Colombier 	fail(pHdrFtrInfo == NULL);
291*25b329d5SDavid du Colombier 
292*25b329d5SDavid du Colombier 	vStartOfParagraphPDF(pDiag, 0);
293*25b329d5SDavid du Colombier 	pStart = pHdrFtrInfo->pText;
294*25b329d5SDavid du Colombier 	while (pStart != NULL) {
295*25b329d5SDavid du Colombier 		pNext = pStart;
296*25b329d5SDavid du Colombier 		while (pNext != NULL &&
297*25b329d5SDavid du Colombier 		       (pNext->tNextFree != 1 ||
298*25b329d5SDavid du Colombier 		        (pNext->szStorage[0] != PAR_END &&
299*25b329d5SDavid du Colombier 		         pNext->szStorage[0] != HARD_RETURN))) {
300*25b329d5SDavid du Colombier 			pNext = pNext->pNext;
301*25b329d5SDavid du Colombier 		}
302*25b329d5SDavid du Colombier 		if (pNext == NULL) {
303*25b329d5SDavid du Colombier 			if (bOutputContainsText(pStart)) {
304*25b329d5SDavid du Colombier 				vAlign2Window(pDiag, pStart,
305*25b329d5SDavid du Colombier 					lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
306*25b329d5SDavid du Colombier 					ALIGNMENT_LEFT);
307*25b329d5SDavid du Colombier 			} else {
308*25b329d5SDavid du Colombier 				vMove2NextLinePDF(pDiag, pStart->usFontSize);
309*25b329d5SDavid du Colombier 			}
310*25b329d5SDavid du Colombier 			break;
311*25b329d5SDavid du Colombier 		}
312*25b329d5SDavid du Colombier 		fail(pNext->tNextFree != 1);
313*25b329d5SDavid du Colombier 		fail(pNext->szStorage[0] != PAR_END &&
314*25b329d5SDavid du Colombier 			pNext->szStorage[0] != HARD_RETURN);
315*25b329d5SDavid du Colombier 
316*25b329d5SDavid du Colombier 		if (pStart != pNext) {
317*25b329d5SDavid du Colombier 			/* There is something to print */
318*25b329d5SDavid du Colombier 			pPrev = pNext->pPrev;
319*25b329d5SDavid du Colombier 			fail(pPrev->pNext != pNext);
320*25b329d5SDavid du Colombier 			/* Cut the chain */
321*25b329d5SDavid du Colombier 			pPrev->pNext = NULL;
322*25b329d5SDavid du Colombier 			if (bOutputContainsText(pStart)) {
323*25b329d5SDavid du Colombier 				/* Print it */
324*25b329d5SDavid du Colombier 				vAlign2Window(pDiag, pStart,
325*25b329d5SDavid du Colombier 					lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
326*25b329d5SDavid du Colombier 					ALIGNMENT_LEFT);
327*25b329d5SDavid du Colombier 			} else {
328*25b329d5SDavid du Colombier 				/* Just an empty line */
329*25b329d5SDavid du Colombier 				vMove2NextLinePDF(pDiag, pStart->usFontSize);
330*25b329d5SDavid du Colombier 			}
331*25b329d5SDavid du Colombier 			/* Repair the chain */
332*25b329d5SDavid du Colombier 			pPrev->pNext = pNext;
333*25b329d5SDavid du Colombier 		}
334*25b329d5SDavid du Colombier 		if (pNext->szStorage[0] == PAR_END) {
335*25b329d5SDavid du Colombier 			vEndOfParagraphPDF(pDiag, pNext->usFontSize,
336*25b329d5SDavid du Colombier 					(long)pNext->usFontSize * 200);
337*25b329d5SDavid du Colombier 		}
338*25b329d5SDavid du Colombier 		pStart = pNext->pNext;
339*25b329d5SDavid du Colombier 	}
340*25b329d5SDavid du Colombier } /* end of vAddHdrFtr */
341*25b329d5SDavid du Colombier 
342*25b329d5SDavid du Colombier /*
343*25b329d5SDavid du Colombier  * vAddHeader - add a page header
344*25b329d5SDavid du Colombier  */
345*25b329d5SDavid du Colombier static void
vAddHeader(diagram_type * pDiag)346*25b329d5SDavid du Colombier vAddHeader(diagram_type *pDiag)
347*25b329d5SDavid du Colombier {
348*25b329d5SDavid du Colombier 	const hdrftr_block_type *pHdrInfo;
349*25b329d5SDavid du Colombier 	const hdrftr_block_type *pFtrInfo;
350*25b329d5SDavid du Colombier 
351*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
352*25b329d5SDavid du Colombier 
353*25b329d5SDavid du Colombier 	NO_DBG_MSG("vAddHeader");
354*25b329d5SDavid du Colombier 
355*25b329d5SDavid du Colombier 	pHdrInfo = pGetHdrFtrInfo(iSectionIndex, TRUE,
356*25b329d5SDavid du Colombier 					odd(iPageCount), bFirstInSection);
357*25b329d5SDavid du Colombier 	pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
358*25b329d5SDavid du Colombier 					odd(iPageCount), bFirstInSection);
359*25b329d5SDavid du Colombier 	/* Set the height of the footer of this page */
360*25b329d5SDavid du Colombier 	lFooterHeight = pFtrInfo == NULL ? 0 : pFtrInfo->lHeight;
361*25b329d5SDavid du Colombier 	fail(lFooterHeight < 0);
362*25b329d5SDavid du Colombier 
363*25b329d5SDavid du Colombier 	if (pHdrInfo == NULL ||
364*25b329d5SDavid du Colombier 	    pHdrInfo->pText == NULL ||
365*25b329d5SDavid du Colombier 	    pHdrInfo->lHeight <= 0) {
366*25b329d5SDavid du Colombier 		fail(pHdrInfo != NULL && pHdrInfo->lHeight < 0);
367*25b329d5SDavid du Colombier 		fail(pHdrInfo != NULL &&
368*25b329d5SDavid du Colombier 			pHdrInfo->pText != NULL &&
369*25b329d5SDavid du Colombier 			pHdrInfo->lHeight == 0);
370*25b329d5SDavid du Colombier 		return;
371*25b329d5SDavid du Colombier 	}
372*25b329d5SDavid du Colombier 
373*25b329d5SDavid du Colombier 	vAddHdrFtr(pDiag, pHdrInfo);
374*25b329d5SDavid du Colombier 
375*25b329d5SDavid du Colombier 	DBG_DEC_C(pHdrInfo->lHeight !=
376*25b329d5SDavid du Colombier 		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
377*25b329d5SDavid du Colombier 		pHdrInfo->lHeight);
378*25b329d5SDavid du Colombier 	DBG_DEC_C(pHdrInfo->lHeight !=
379*25b329d5SDavid du Colombier 		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
380*25b329d5SDavid du Colombier 		lPageHeight - PS_TOP_MARGIN - pDiag->lYtop);
381*25b329d5SDavid du Colombier } /* end of vAddHeader */
382*25b329d5SDavid du Colombier 
383*25b329d5SDavid du Colombier /*
384*25b329d5SDavid du Colombier  * vAddFooter - add a page footer
385*25b329d5SDavid du Colombier  */
386*25b329d5SDavid du Colombier static void
vAddFooter(diagram_type * pDiag)387*25b329d5SDavid du Colombier vAddFooter(diagram_type *pDiag)
388*25b329d5SDavid du Colombier {
389*25b329d5SDavid du Colombier 	const hdrftr_block_type *pFtrInfo;
390*25b329d5SDavid du Colombier 
391*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
392*25b329d5SDavid du Colombier 
393*25b329d5SDavid du Colombier 	NO_DBG_MSG("vAddFooter");
394*25b329d5SDavid du Colombier 
395*25b329d5SDavid du Colombier 	pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
396*25b329d5SDavid du Colombier 					odd(iPageCount), bFirstInSection);
397*25b329d5SDavid du Colombier 	bFirstInSection = FALSE;
398*25b329d5SDavid du Colombier 	if (pFtrInfo == NULL ||
399*25b329d5SDavid du Colombier 	    pFtrInfo->pText == NULL ||
400*25b329d5SDavid du Colombier 	    pFtrInfo->lHeight <= 0) {
401*25b329d5SDavid du Colombier 		fail(pFtrInfo != NULL && pFtrInfo->lHeight < 0);
402*25b329d5SDavid du Colombier 		fail(pFtrInfo != NULL &&
403*25b329d5SDavid du Colombier 			pFtrInfo->pText != NULL &&
404*25b329d5SDavid du Colombier 			pFtrInfo->lHeight == 0);
405*25b329d5SDavid du Colombier 		return;
406*25b329d5SDavid du Colombier 	}
407*25b329d5SDavid du Colombier 
408*25b329d5SDavid du Colombier 	bInFtrSpace = TRUE;
409*25b329d5SDavid du Colombier 
410*25b329d5SDavid du Colombier 	DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, pFtrInfo->lHeight);
411*25b329d5SDavid du Colombier 	DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, lFooterHeight);
412*25b329d5SDavid du Colombier 	DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
413*25b329d5SDavid du Colombier 			pDiag->lYtop);
414*25b329d5SDavid du Colombier 	DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
415*25b329d5SDavid du Colombier 			lFooterHeight + PS_BOTTOM_MARGIN);
416*25b329d5SDavid du Colombier 
417*25b329d5SDavid du Colombier 	if (pDiag->lYtop > lFooterHeight + PS_BOTTOM_MARGIN) {
418*25b329d5SDavid du Colombier 		/* Move down to the start of the footer */
419*25b329d5SDavid du Colombier 		pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
420*25b329d5SDavid du Colombier 		vMoveTo(pDiag, 0);
421*25b329d5SDavid du Colombier 	} else if (pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN / 2) {
422*25b329d5SDavid du Colombier 		DBG_FIXME();
423*25b329d5SDavid du Colombier 		/*
424*25b329d5SDavid du Colombier 		 * Move up to the start of the footer, to prevent moving
425*25b329d5SDavid du Colombier 		 * of the bottom edge of the paper
426*25b329d5SDavid du Colombier 		 */
427*25b329d5SDavid du Colombier 		pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
428*25b329d5SDavid du Colombier 		vMoveTo(pDiag, 0);
429*25b329d5SDavid du Colombier 	}
430*25b329d5SDavid du Colombier 
431*25b329d5SDavid du Colombier 	DBG_FLT_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
432*25b329d5SDavid du Colombier 	dDrawUnits2Points(lFooterHeight + PS_BOTTOM_MARGIN - pDiag->lYtop));
433*25b329d5SDavid du Colombier 
434*25b329d5SDavid du Colombier 	vAddHdrFtr(pDiag, pFtrInfo);
435*25b329d5SDavid du Colombier 	bInFtrSpace = FALSE;
436*25b329d5SDavid du Colombier } /* end of vAddFooter */
437*25b329d5SDavid du Colombier 
438*25b329d5SDavid du Colombier /*
439*25b329d5SDavid du Colombier  * vEndPageObject - end the current page object
440*25b329d5SDavid du Colombier  */
441*25b329d5SDavid du Colombier static void
vEndPageObject(FILE * pOutFile)442*25b329d5SDavid du Colombier vEndPageObject(FILE *pOutFile)
443*25b329d5SDavid du Colombier {
444*25b329d5SDavid du Colombier 	long	lStreamEnd;
445*25b329d5SDavid du Colombier 
446*25b329d5SDavid du Colombier 	if (lStreamStart < 0) {
447*25b329d5SDavid du Colombier 		/* There is no current page object */
448*25b329d5SDavid du Colombier 		return;
449*25b329d5SDavid du Colombier 	}
450*25b329d5SDavid du Colombier 
451*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "ET\n");
452*25b329d5SDavid du Colombier 	lStreamEnd = lFilePosition;
453*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endstream\n");
454*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endobj\n");
455*25b329d5SDavid du Colombier 
456*25b329d5SDavid du Colombier 	iObjectNumberCurr++;
457*25b329d5SDavid du Colombier 	vSetLocation(iObjectNumberCurr);
458*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
459*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "%lu\n", lStreamEnd - lStreamStart);
460*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endobj\n");
461*25b329d5SDavid du Colombier } /* end of vEndPageObject */
462*25b329d5SDavid du Colombier 
463*25b329d5SDavid du Colombier /*
464*25b329d5SDavid du Colombier  * vMove2NextPage - move to the start of the next page
465*25b329d5SDavid du Colombier  */
466*25b329d5SDavid du Colombier static void
vMove2NextPage(diagram_type * pDiag,BOOL bNewSection)467*25b329d5SDavid du Colombier vMove2NextPage(diagram_type *pDiag, BOOL bNewSection)
468*25b329d5SDavid du Colombier {
469*25b329d5SDavid du Colombier 	FILE	*pOutFile;
470*25b329d5SDavid du Colombier 
471*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
472*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
473*25b329d5SDavid du Colombier 
474*25b329d5SDavid du Colombier 	pOutFile = pDiag->pOutFile;
475*25b329d5SDavid du Colombier 
476*25b329d5SDavid du Colombier 	vAddFooter(pDiag);
477*25b329d5SDavid du Colombier 	/* End the old page object */
478*25b329d5SDavid du Colombier 	vEndPageObject(pOutFile);
479*25b329d5SDavid du Colombier 	if (bNewSection) {
480*25b329d5SDavid du Colombier 		iSectionIndex++;
481*25b329d5SDavid du Colombier 		bFirstInSection = TRUE;
482*25b329d5SDavid du Colombier 	}
483*25b329d5SDavid du Colombier 
484*25b329d5SDavid du Colombier 	/* Start the new page object */
485*25b329d5SDavid du Colombier 	iObjectNumberCurr++;
486*25b329d5SDavid du Colombier 	vSetLocation(iObjectNumberCurr);
487*25b329d5SDavid du Colombier 	vFillNextPageObject();
488*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
489*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<<\n");
490*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Type /Page\n");
491*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Parent 3 0 R\n");
492*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Resources 17 0 R\n");
493*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Contents %d 0 R\n", iObjectNumberCurr + 1);
494*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, ">>\n");
495*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endobj\n");
496*25b329d5SDavid du Colombier 
497*25b329d5SDavid du Colombier 	/* Start the new text object */
498*25b329d5SDavid du Colombier 	iObjectNumberCurr++;
499*25b329d5SDavid du Colombier 	vSetLocation(iObjectNumberCurr);
500*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
501*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<<\n");
502*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Length %d 0 R\n", iObjectNumberCurr + 1);
503*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, ">>\n");
504*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "stream\n");
505*25b329d5SDavid du Colombier 	lStreamStart = lFilePosition;
506*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "BT\n");
507*25b329d5SDavid du Colombier 
508*25b329d5SDavid du Colombier 	/* Set variables to their start of page values */
509*25b329d5SDavid du Colombier 	pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
510*25b329d5SDavid du Colombier 	tFontRefCurr = (drawfile_fontref)-1;
511*25b329d5SDavid du Colombier 	usFontSizeCurr = 0;
512*25b329d5SDavid du Colombier 	iFontColorCurr = -1;
513*25b329d5SDavid du Colombier 	lYtopCurr = -1;
514*25b329d5SDavid du Colombier 	vAddHeader(pDiag);
515*25b329d5SDavid du Colombier } /* end of vMove2NextPage */
516*25b329d5SDavid du Colombier 
517*25b329d5SDavid du Colombier /*
518*25b329d5SDavid du Colombier  * vMoveTo - move to the specified X,Y coordinates
519*25b329d5SDavid du Colombier  *
520*25b329d5SDavid du Colombier  * Move the current position of the specified diagram to its X,Y coordinates,
521*25b329d5SDavid du Colombier  * start on a new page if needed
522*25b329d5SDavid du Colombier  */
523*25b329d5SDavid du Colombier static void
vMoveTo(diagram_type * pDiag,long lLastVerticalMovement)524*25b329d5SDavid du Colombier vMoveTo(diagram_type *pDiag, long lLastVerticalMovement)
525*25b329d5SDavid du Colombier {
526*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
527*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
528*25b329d5SDavid du Colombier 
529*25b329d5SDavid du Colombier 	if (pDiag->lYtop <= lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace) {
530*25b329d5SDavid du Colombier 		vMove2NextPage(pDiag, FALSE);
531*25b329d5SDavid du Colombier 		/* Repeat the last vertical movement on the new page */
532*25b329d5SDavid du Colombier 		pDiag->lYtop -= lLastVerticalMovement;
533*25b329d5SDavid du Colombier 	}
534*25b329d5SDavid du Colombier 
535*25b329d5SDavid du Colombier 	fail(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace);
536*25b329d5SDavid du Colombier 	DBG_DEC_C(pDiag->lYtop < PS_BOTTOM_MARGIN, pDiag->lYtop);
537*25b329d5SDavid du Colombier 	fail(pDiag->lYtop < PS_BOTTOM_MARGIN / 3);
538*25b329d5SDavid du Colombier 
539*25b329d5SDavid du Colombier 	if (pDiag->lYtop != lYtopCurr) {
540*25b329d5SDavid du Colombier 		vFPprintf(pDiag->pOutFile, "1 0 0 1 %.2f %.2f Tm\n",
541*25b329d5SDavid du Colombier 			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
542*25b329d5SDavid du Colombier 			dDrawUnits2Points(pDiag->lYtop));
543*25b329d5SDavid du Colombier 		lYtopCurr = pDiag->lYtop;
544*25b329d5SDavid du Colombier 	}
545*25b329d5SDavid du Colombier } /* end of vMoveTo */
546*25b329d5SDavid du Colombier 
547*25b329d5SDavid du Colombier /*
548*25b329d5SDavid du Colombier  * vProloguePDF - set options and perform the PDF initialization
549*25b329d5SDavid du Colombier  */
550*25b329d5SDavid du Colombier void
vProloguePDF(diagram_type * pDiag,const char * szTask,const options_type * pOptions)551*25b329d5SDavid du Colombier vProloguePDF(diagram_type *pDiag,
552*25b329d5SDavid du Colombier 	const char *szTask, const options_type *pOptions)
553*25b329d5SDavid du Colombier {
554*25b329d5SDavid du Colombier 	FILE	*pOutFile;
555*25b329d5SDavid du Colombier 
556*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
557*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
558*25b329d5SDavid du Colombier 	fail(pOptions == NULL);
559*25b329d5SDavid du Colombier 
560*25b329d5SDavid du Colombier 	pOutFile = pDiag->pOutFile;
561*25b329d5SDavid du Colombier 
562*25b329d5SDavid du Colombier 	eEncoding = pOptions->eEncoding;
563*25b329d5SDavid du Colombier 
564*25b329d5SDavid du Colombier 	/* Create an empty location array */
565*25b329d5SDavid du Colombier 	tLocations = INITIAL_LOCATION_SIZE;
566*25b329d5SDavid du Colombier 	alLocation = xcalloc(tLocations, sizeof(long));
567*25b329d5SDavid du Colombier 
568*25b329d5SDavid du Colombier 	/* Create an empty pageobject array */
569*25b329d5SDavid du Colombier 	tMaxPageObjects = INITIAL_PAGEOBJECT_SIZE;
570*25b329d5SDavid du Colombier 	aiPageObject = xcalloc(tMaxPageObjects, sizeof(int));
571*25b329d5SDavid du Colombier 
572*25b329d5SDavid du Colombier 	if (pOptions->iPageHeight == INT_MAX) {
573*25b329d5SDavid du Colombier 		lPageHeight = LONG_MAX;
574*25b329d5SDavid du Colombier 	} else {
575*25b329d5SDavid du Colombier 		lPageHeight = lPoints2DrawUnits(pOptions->iPageHeight);
576*25b329d5SDavid du Colombier 	}
577*25b329d5SDavid du Colombier 	DBG_DEC(lPageHeight);
578*25b329d5SDavid du Colombier 	if (pOptions->iPageWidth == INT_MAX) {
579*25b329d5SDavid du Colombier 		lPageWidth = LONG_MAX;
580*25b329d5SDavid du Colombier 	} else {
581*25b329d5SDavid du Colombier 		lPageWidth = lPoints2DrawUnits(pOptions->iPageWidth);
582*25b329d5SDavid du Colombier 	}
583*25b329d5SDavid du Colombier 	DBG_DEC(lPageWidth);
584*25b329d5SDavid du Colombier 	lFooterHeight = 0;
585*25b329d5SDavid du Colombier 	bInFtrSpace = FALSE;
586*25b329d5SDavid du Colombier 
587*25b329d5SDavid du Colombier 	tFontRefCurr = (drawfile_fontref)-1;
588*25b329d5SDavid du Colombier 	usFontSizeCurr = 0;
589*25b329d5SDavid du Colombier 	iFontColorCurr = -1;
590*25b329d5SDavid du Colombier 	lYtopCurr = -1;
591*25b329d5SDavid du Colombier 	iPageCount = 0;
592*25b329d5SDavid du Colombier 	iImageCount = 0;
593*25b329d5SDavid du Colombier 	iSectionIndex = 0;
594*25b329d5SDavid du Colombier 	bFirstInSection = TRUE;
595*25b329d5SDavid du Colombier 	lFilePosition = 0;
596*25b329d5SDavid du Colombier 	iMaxLocationNumber = 0;
597*25b329d5SDavid du Colombier 	lStreamStart = -1;
598*25b329d5SDavid du Colombier 	iObjectNumberCurr = 17;
599*25b329d5SDavid du Colombier 	pDiag->lXleft = 0;
600*25b329d5SDavid du Colombier 	pDiag->lYtop = 0;
601*25b329d5SDavid du Colombier 
602*25b329d5SDavid du Colombier 	szProducer = szTask;
603*25b329d5SDavid du Colombier 
604*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "%%PDF-1.3\n");
605*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "%%%c%c%c%c\n", 0xe2, 0xe3, 0xcf, 0xd3);
606*25b329d5SDavid du Colombier 
607*25b329d5SDavid du Colombier 	/* Root catalog */
608*25b329d5SDavid du Colombier 	vSetLocation(1);
609*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "1 0 obj\n");
610*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<<\n");
611*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Type /Catalog\n");
612*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Pages 3 0 R\n");
613*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, ">>\n");
614*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endobj\n");
615*25b329d5SDavid du Colombier } /* end of vProloguePDF */
616*25b329d5SDavid du Colombier 
617*25b329d5SDavid du Colombier /*
618*25b329d5SDavid du Colombier  * vEpiloguePDF - clean up after everything is done
619*25b329d5SDavid du Colombier  */
620*25b329d5SDavid du Colombier void
vEpiloguePDF(diagram_type * pDiag)621*25b329d5SDavid du Colombier vEpiloguePDF(diagram_type *pDiag)
622*25b329d5SDavid du Colombier {
623*25b329d5SDavid du Colombier 	FILE	*pOutFile;
624*25b329d5SDavid du Colombier 	long	lXref;
625*25b329d5SDavid du Colombier 	int	iIndex;
626*25b329d5SDavid du Colombier 
627*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
628*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
629*25b329d5SDavid du Colombier 
630*25b329d5SDavid du Colombier 	pOutFile = pDiag->pOutFile;
631*25b329d5SDavid du Colombier 
632*25b329d5SDavid du Colombier 	vAddFooter(pDiag);
633*25b329d5SDavid du Colombier 	/* End the old page object */
634*25b329d5SDavid du Colombier 	vEndPageObject(pOutFile);
635*25b329d5SDavid du Colombier 
636*25b329d5SDavid du Colombier 	vSetLocation(3);
637*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "3 0 obj\n");
638*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<<\n");
639*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Type /Pages\n");
640*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Count %d\n", iPageCount);
641*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/MediaBox [ 0 0 %.0f %.0f ]\n",
642*25b329d5SDavid du Colombier 			dDrawUnits2Points(lPageWidth),
643*25b329d5SDavid du Colombier 			dDrawUnits2Points(lPageHeight));
644*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Kids [ ");
645*25b329d5SDavid du Colombier 	for (iIndex = 1; iIndex <= iPageCount; iIndex++) {
646*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t%d 0 R\n", aiPageObject[iIndex]);
647*25b329d5SDavid du Colombier 	}
648*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "]\n");
649*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, ">>\n");
650*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endobj\n");
651*25b329d5SDavid du Colombier 
652*25b329d5SDavid du Colombier 	lXref = lFilePosition;
653*25b329d5SDavid du Colombier 
654*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "xref\n");
655*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "0 %d\n", iMaxLocationNumber + 1);
656*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "0000000000 65535 f \n");
657*25b329d5SDavid du Colombier 	for (iIndex = 1; iIndex <= iMaxLocationNumber; iIndex++) {
658*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "%.10ld 00000 n \n", alLocation[iIndex]);
659*25b329d5SDavid du Colombier 	}
660*25b329d5SDavid du Colombier 
661*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "trailer\n");
662*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<<\n");
663*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Size %d\n", iMaxLocationNumber + 1);
664*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Root 1 0 R\n");
665*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Info 2 0 R\n");
666*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, ">>\n");
667*25b329d5SDavid du Colombier 
668*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "startxref\n");
669*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "%ld\n", lXref);
670*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "%%%%EOF\n");
671*25b329d5SDavid du Colombier 
672*25b329d5SDavid du Colombier 	szProducer = NULL;
673*25b329d5SDavid du Colombier 	aiPageObject = xfree(aiPageObject);
674*25b329d5SDavid du Colombier 	alLocation = xfree(alLocation);
675*25b329d5SDavid du Colombier } /* end of vEpiloguePDF */
676*25b329d5SDavid du Colombier 
677*25b329d5SDavid du Colombier /*
678*25b329d5SDavid du Colombier  * vPrintPalette - print a pdf color space (palette)
679*25b329d5SDavid du Colombier  */
680*25b329d5SDavid du Colombier static void
vPrintPalette(FILE * pOutFile,const imagedata_type * pImg)681*25b329d5SDavid du Colombier vPrintPalette(FILE *pOutFile, const imagedata_type *pImg)
682*25b329d5SDavid du Colombier {
683*25b329d5SDavid du Colombier 	int	iIndex;
684*25b329d5SDavid du Colombier 
685*25b329d5SDavid du Colombier 	fail(pOutFile == NULL);
686*25b329d5SDavid du Colombier 	fail(pImg == NULL);
687*25b329d5SDavid du Colombier 	fail(pImg->iColorsUsed < 2);
688*25b329d5SDavid du Colombier 	fail(pImg->iColorsUsed > 256);
689*25b329d5SDavid du Colombier 
690*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\t/ColorSpace [ /Indexed\n");
691*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\t/Device%s %d\n",
692*25b329d5SDavid du Colombier 		pImg->bColorImage ? "RGB" : "Gray", pImg->iColorsUsed - 1);
693*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<");
694*25b329d5SDavid du Colombier 	for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
695*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "%02x",
696*25b329d5SDavid du Colombier 				(unsigned int)pImg->aucPalette[iIndex][0]);
697*25b329d5SDavid du Colombier 		if (pImg->bColorImage) {
698*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "%02x%02x",
699*25b329d5SDavid du Colombier 				(unsigned int)pImg->aucPalette[iIndex][1],
700*25b329d5SDavid du Colombier 				(unsigned int)pImg->aucPalette[iIndex][2]);
701*25b329d5SDavid du Colombier 		}
702*25b329d5SDavid du Colombier 		if (iIndex % 8 == 7) {
703*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\n");
704*25b329d5SDavid du Colombier 		} else {
705*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, " ");
706*25b329d5SDavid du Colombier 		}
707*25b329d5SDavid du Colombier 	}
708*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "> ]\n");
709*25b329d5SDavid du Colombier } /* end of vPrintPalette */
710*25b329d5SDavid du Colombier 
711*25b329d5SDavid du Colombier /*
712*25b329d5SDavid du Colombier  * vImageProloguePDF - perform the image initialization
713*25b329d5SDavid du Colombier  */
714*25b329d5SDavid du Colombier void
vImageProloguePDF(diagram_type * pDiag,const imagedata_type * pImg)715*25b329d5SDavid du Colombier vImageProloguePDF(diagram_type *pDiag, const imagedata_type *pImg)
716*25b329d5SDavid du Colombier {
717*25b329d5SDavid du Colombier 	FILE	*pOutFile;
718*25b329d5SDavid du Colombier 
719*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
720*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
721*25b329d5SDavid du Colombier 	fail(pImg == NULL);
722*25b329d5SDavid du Colombier 
723*25b329d5SDavid du Colombier 	if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
724*25b329d5SDavid du Colombier 		return;
725*25b329d5SDavid du Colombier 	}
726*25b329d5SDavid du Colombier 
727*25b329d5SDavid du Colombier 	iImageCount++;
728*25b329d5SDavid du Colombier 
729*25b329d5SDavid du Colombier 	DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
730*25b329d5SDavid du Colombier 
731*25b329d5SDavid du Colombier 	pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
732*25b329d5SDavid du Colombier 	vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
733*25b329d5SDavid du Colombier 
734*25b329d5SDavid du Colombier 	pOutFile = pDiag->pOutFile;
735*25b329d5SDavid du Colombier 
736*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "ET\n");
737*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "q %% Image %03d\n", iImageCount);
738*25b329d5SDavid du Colombier 	if (pImg->eImageType == imagetype_is_dib) {
739*25b329d5SDavid du Colombier 		/* Scanning from left to right and bottom to top */
740*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "%d 0 0 %d %.2f %.2f cm\n",
741*25b329d5SDavid du Colombier 			pImg->iHorSizeScaled, -pImg->iVerSizeScaled,
742*25b329d5SDavid du Colombier 			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
743*25b329d5SDavid du Colombier 			dDrawUnits2Points(pDiag->lYtop) + pImg->iVerSizeScaled);
744*25b329d5SDavid du Colombier 	} else {
745*25b329d5SDavid du Colombier 		/* Scanning from left to right and top to bottom */
746*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "%d 0 0 %d %.2f %.2f cm\n",
747*25b329d5SDavid du Colombier 			pImg->iHorSizeScaled, pImg->iVerSizeScaled,
748*25b329d5SDavid du Colombier 			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
749*25b329d5SDavid du Colombier 			dDrawUnits2Points(pDiag->lYtop));
750*25b329d5SDavid du Colombier 	}
751*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "BI\n");
752*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\t/Width %d\n", pImg->iWidth);
753*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\t/Height %d\n", pImg->iHeight);
754*25b329d5SDavid du Colombier 	switch (pImg->eImageType) {
755*25b329d5SDavid du Colombier 	case imagetype_is_jpeg:
756*25b329d5SDavid du Colombier 		switch (pImg->iComponents) {
757*25b329d5SDavid du Colombier 		case 1:
758*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/ColorSpace /DeviceGray\n");
759*25b329d5SDavid du Colombier 			break;
760*25b329d5SDavid du Colombier 		case 3:
761*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
762*25b329d5SDavid du Colombier 			break;
763*25b329d5SDavid du Colombier 		case 4:
764*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/ColorSpace /DeviceCMYK\n");
765*25b329d5SDavid du Colombier 			if (pImg->bAdobe) {
766*25b329d5SDavid du Colombier 				/*
767*25b329d5SDavid du Colombier 				 * Adobe-conforming CMYK file
768*25b329d5SDavid du Colombier 				 * applying workaround for color inversion
769*25b329d5SDavid du Colombier 				 */
770*25b329d5SDavid du Colombier 				vFPprintf(pOutFile,
771*25b329d5SDavid du Colombier 					"\t/Decode [1 0 1 0 1 0 1 0]\n");
772*25b329d5SDavid du Colombier 			}
773*25b329d5SDavid du Colombier 			break;
774*25b329d5SDavid du Colombier 		default:
775*25b329d5SDavid du Colombier 			DBG_DEC(pImg->iComponents);
776*25b329d5SDavid du Colombier 			break;
777*25b329d5SDavid du Colombier 		}
778*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
779*25b329d5SDavid du Colombier 		vFPprintf(pOutFile,
780*25b329d5SDavid du Colombier 			"\t/Filter [ /ASCII85Decode /DCTDecode ]\n");
781*25b329d5SDavid du Colombier 		break;
782*25b329d5SDavid du Colombier 	case imagetype_is_png:
783*25b329d5SDavid du Colombier 		if (pImg->iComponents == 3 || pImg->iComponents == 4) {
784*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
785*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
786*25b329d5SDavid du Colombier 		} else if (pImg->iColorsUsed > 0) {
787*25b329d5SDavid du Colombier 			vPrintPalette(pOutFile, pImg);
788*25b329d5SDavid du Colombier 			fail(pImg->uiBitsPerComponent > 8);
789*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/BitsPerComponent %u\n",
790*25b329d5SDavid du Colombier 					pImg->uiBitsPerComponent);
791*25b329d5SDavid du Colombier 		} else {
792*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/ColorSpace /DeviceGray\n");
793*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
794*25b329d5SDavid du Colombier 		}
795*25b329d5SDavid du Colombier 		vFPprintf(pOutFile,
796*25b329d5SDavid du Colombier 			"\t/Filter [ /ASCII85Decode /FlateDecode ]\n");
797*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t/DecodeParms [ null <<\n");
798*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t\t/Predictor 10\n");
799*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t\t/Colors %d\n", pImg->iComponents);
800*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t\t/BitsPerComponent %u\n",
801*25b329d5SDavid du Colombier 						pImg->uiBitsPerComponent);
802*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t\t/Columns %d\n", pImg->iWidth);
803*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t\t>> ]\n");
804*25b329d5SDavid du Colombier 		break;
805*25b329d5SDavid du Colombier 	case imagetype_is_dib:
806*25b329d5SDavid du Colombier 		if (pImg->uiBitsPerComponent <= 8) {
807*25b329d5SDavid du Colombier 			vPrintPalette(pOutFile, pImg);
808*25b329d5SDavid du Colombier 		} else {
809*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
810*25b329d5SDavid du Colombier 		}
811*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
812*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t/Filter /ASCII85Decode\n");
813*25b329d5SDavid du Colombier 		break;
814*25b329d5SDavid du Colombier 	default:
815*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t/ColorSpace /Device%s\n",
816*25b329d5SDavid du Colombier 			pImg->bColorImage ? "RGB" : "Gray");
817*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
818*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t/Filter /ASCIIHexDecode\n");
819*25b329d5SDavid du Colombier 		break;
820*25b329d5SDavid du Colombier 	}
821*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "ID\n");
822*25b329d5SDavid du Colombier } /* end of vImageProloguePDF */
823*25b329d5SDavid du Colombier 
824*25b329d5SDavid du Colombier /*
825*25b329d5SDavid du Colombier  * vImageEpiloguePDF - clean up after the image
826*25b329d5SDavid du Colombier  */
827*25b329d5SDavid du Colombier void
vImageEpiloguePDF(diagram_type * pDiag)828*25b329d5SDavid du Colombier vImageEpiloguePDF(diagram_type *pDiag)
829*25b329d5SDavid du Colombier {
830*25b329d5SDavid du Colombier 	FILE	*pOutFile;
831*25b329d5SDavid du Colombier 
832*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
833*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
834*25b329d5SDavid du Colombier 
835*25b329d5SDavid du Colombier 	pOutFile = pDiag->pOutFile;
836*25b329d5SDavid du Colombier 
837*25b329d5SDavid du Colombier 	/* Correction for the image bytes */
838*25b329d5SDavid du Colombier 	lFilePosition = ftell(pOutFile);
839*25b329d5SDavid du Colombier 
840*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "EI\n");
841*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "Q\n");
842*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "BT\n");
843*25b329d5SDavid du Colombier 
844*25b329d5SDavid du Colombier 	pDiag->lXleft = 0;
845*25b329d5SDavid du Colombier } /* end of vImageEpiloguePDF */
846*25b329d5SDavid du Colombier 
847*25b329d5SDavid du Colombier /*
848*25b329d5SDavid du Colombier  * bAddDummyImagePDF - add a dummy image
849*25b329d5SDavid du Colombier  *
850*25b329d5SDavid du Colombier  * return TRUE when successful, otherwise FALSE
851*25b329d5SDavid du Colombier  */
852*25b329d5SDavid du Colombier BOOL
bAddDummyImagePDF(diagram_type * pDiag,const imagedata_type * pImg)853*25b329d5SDavid du Colombier bAddDummyImagePDF(diagram_type *pDiag, const imagedata_type *pImg)
854*25b329d5SDavid du Colombier {
855*25b329d5SDavid du Colombier 	FILE	*pOutFile;
856*25b329d5SDavid du Colombier 
857*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
858*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
859*25b329d5SDavid du Colombier 	fail(pImg == NULL);
860*25b329d5SDavid du Colombier 
861*25b329d5SDavid du Colombier 	if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
862*25b329d5SDavid du Colombier 		return FALSE;
863*25b329d5SDavid du Colombier 	}
864*25b329d5SDavid du Colombier 
865*25b329d5SDavid du Colombier 	iImageCount++;
866*25b329d5SDavid du Colombier 
867*25b329d5SDavid du Colombier 	DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
868*25b329d5SDavid du Colombier 
869*25b329d5SDavid du Colombier 	pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
870*25b329d5SDavid du Colombier 	vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
871*25b329d5SDavid du Colombier 
872*25b329d5SDavid du Colombier 	pOutFile = pDiag->pOutFile;
873*25b329d5SDavid du Colombier 
874*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "ET\n");
875*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "q %% Image %03d\n", iImageCount);
876*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\t1.0 w\n");
877*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\t0.3 G\n");
878*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\t%.2f %.2f %d %d re\n",
879*25b329d5SDavid du Colombier 			dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
880*25b329d5SDavid du Colombier 			dDrawUnits2Points(pDiag->lYtop),
881*25b329d5SDavid du Colombier 			pImg->iHorSizeScaled,
882*25b329d5SDavid du Colombier 			pImg->iVerSizeScaled);
883*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\tS\n");
884*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "Q\n");
885*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "BT\n");
886*25b329d5SDavid du Colombier 
887*25b329d5SDavid du Colombier 	pDiag->lXleft = 0;
888*25b329d5SDavid du Colombier 
889*25b329d5SDavid du Colombier 	return TRUE;
890*25b329d5SDavid du Colombier } /* end of bAddDummyImagePDF */
891*25b329d5SDavid du Colombier 
892*25b329d5SDavid du Colombier /*
893*25b329d5SDavid du Colombier  * vAddFontsPDF - add the font information
894*25b329d5SDavid du Colombier  */
895*25b329d5SDavid du Colombier void
vAddFontsPDF(diagram_type * pDiag)896*25b329d5SDavid du Colombier vAddFontsPDF(diagram_type *pDiag)
897*25b329d5SDavid du Colombier {
898*25b329d5SDavid du Colombier 	FILE	*pOutFile;
899*25b329d5SDavid du Colombier 	size_t	tIndex;
900*25b329d5SDavid du Colombier 
901*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
902*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
903*25b329d5SDavid du Colombier 
904*25b329d5SDavid du Colombier 	pOutFile = pDiag->pOutFile;
905*25b329d5SDavid du Colombier 
906*25b329d5SDavid du Colombier 	/* The font encoding */
907*25b329d5SDavid du Colombier 	vSetLocation(4);
908*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "4 0 obj\n");
909*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<<\n");
910*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Type /Encoding\n");
911*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/BaseEncoding /StandardEncoding\n");
912*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Differences [\n");
913*25b329d5SDavid du Colombier 	switch (eEncoding) {
914*25b329d5SDavid du Colombier 	case encoding_latin_1:
915*25b329d5SDavid du Colombier 		for (tIndex = 0;
916*25b329d5SDavid du Colombier 		     tIndex < elementsof(iso_8859_1);
917*25b329d5SDavid du Colombier 		     tIndex++) {
918*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "%s\n", iso_8859_1[tIndex]);
919*25b329d5SDavid du Colombier 		}
920*25b329d5SDavid du Colombier 		break;
921*25b329d5SDavid du Colombier 	case encoding_latin_2:
922*25b329d5SDavid du Colombier 		for (tIndex = 0;
923*25b329d5SDavid du Colombier 		     tIndex < elementsof(iso_8859_2);
924*25b329d5SDavid du Colombier 		     tIndex++) {
925*25b329d5SDavid du Colombier 			vFPprintf(pOutFile, "%s\n", iso_8859_2[tIndex]);
926*25b329d5SDavid du Colombier 		}
927*25b329d5SDavid du Colombier 		break;
928*25b329d5SDavid du Colombier 	case encoding_cyrillic:
929*25b329d5SDavid du Colombier 		werr(1,
930*25b329d5SDavid du Colombier 		"The combination PDF and Cyrillic is not supported");
931*25b329d5SDavid du Colombier 		break;
932*25b329d5SDavid du Colombier 	case encoding_utf_8:
933*25b329d5SDavid du Colombier 		werr(1,
934*25b329d5SDavid du Colombier 		"The combination PDF and UTF-8 is not supported");
935*25b329d5SDavid du Colombier 		break;
936*25b329d5SDavid du Colombier 	default:
937*25b329d5SDavid du Colombier 		DBG_DEC(eEncoding);
938*25b329d5SDavid du Colombier 		break;
939*25b329d5SDavid du Colombier 	}
940*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "]\n");
941*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, ">>\n");
942*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endobj\n");
943*25b329d5SDavid du Colombier 
944*25b329d5SDavid du Colombier 	/* Twelve of the standard type 1 fonts */
945*25b329d5SDavid du Colombier 	for (tIndex = 0; tIndex < 12; tIndex++) {
946*25b329d5SDavid du Colombier 		vSetLocation(5 + tIndex);
947*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "%u 0 obj\n", 5 + tIndex);
948*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "<<\n");
949*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/Type /Font\n");
950*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/Subtype /Type1\n");
951*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/Name /F%u\n", 1 + tIndex);
952*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/BaseFont /%s\n",
953*25b329d5SDavid du Colombier 						atFontname[tIndex].szPDFname);
954*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "/Encoding 4 0 R\n");
955*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, ">>\n");
956*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "endobj\n");
957*25b329d5SDavid du Colombier 	}
958*25b329d5SDavid du Colombier 
959*25b329d5SDavid du Colombier 	/* The Resources */
960*25b329d5SDavid du Colombier 	vSetLocation(17);
961*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "17 0 obj\n");
962*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "<<\n");
963*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/ProcSet [ /PDF /Text ]\n");
964*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "/Font <<\n");
965*25b329d5SDavid du Colombier 	for (tIndex = 0; tIndex < 12; tIndex++) {
966*25b329d5SDavid du Colombier 		vFPprintf(pOutFile, "\t/F%u %u 0 R\n", 1 + tIndex, 5 + tIndex);
967*25b329d5SDavid du Colombier 	}
968*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "\t>>\n");
969*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, ">>\n");
970*25b329d5SDavid du Colombier 	vFPprintf(pOutFile, "endobj\n");
971*25b329d5SDavid du Colombier 	vAddHeader(pDiag);
972*25b329d5SDavid du Colombier } /* end of vAddFontsPDF */
973*25b329d5SDavid du Colombier 
974*25b329d5SDavid du Colombier /*
975*25b329d5SDavid du Colombier  * vPrintPDF - print a PDF string
976*25b329d5SDavid du Colombier  */
977*25b329d5SDavid du Colombier static void
vPrintPDF(FILE * pFile,const char * szString,size_t tStringLength,USHORT usFontstyle)978*25b329d5SDavid du Colombier vPrintPDF(FILE *pFile, const char *szString, size_t tStringLength,
979*25b329d5SDavid du Colombier 	USHORT usFontstyle)
980*25b329d5SDavid du Colombier {
981*25b329d5SDavid du Colombier 	const UCHAR	*aucBytes;
982*25b329d5SDavid du Colombier 	double	dMove;
983*25b329d5SDavid du Colombier 	size_t	tCount;
984*25b329d5SDavid du Colombier 
985*25b329d5SDavid du Colombier 	fail(szString == NULL);
986*25b329d5SDavid du Colombier 
987*25b329d5SDavid du Colombier 	if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
988*25b329d5SDavid du Colombier 		return;
989*25b329d5SDavid du Colombier 	}
990*25b329d5SDavid du Colombier 	DBG_DEC_C(usFontSizeCurr < MIN_FONT_SIZE, usFontSizeCurr);
991*25b329d5SDavid du Colombier 
992*25b329d5SDavid du Colombier 	dMove = 0.0;
993*25b329d5SDavid du Colombier 
994*25b329d5SDavid du Colombier 	/* Up for superscript */
995*25b329d5SDavid du Colombier 	if (bIsSuperscript(usFontstyle) && usFontSizeCurr != 0) {
996*25b329d5SDavid du Colombier 		dMove = (double)((usFontSizeCurr + 1) / 2) * 0.375;
997*25b329d5SDavid du Colombier 		vFPprintf(pFile, "%.2f Ts\n", dMove);
998*25b329d5SDavid du Colombier 	}
999*25b329d5SDavid du Colombier 
1000*25b329d5SDavid du Colombier 	/* Down for subscript */
1001*25b329d5SDavid du Colombier 	if (bIsSubscript(usFontstyle) && usFontSizeCurr != 0) {
1002*25b329d5SDavid du Colombier 		dMove = (double)usFontSizeCurr * 0.125;
1003*25b329d5SDavid du Colombier 		vFPprintf(pFile, "%.2f Ts\n", -dMove);
1004*25b329d5SDavid du Colombier 	}
1005*25b329d5SDavid du Colombier 
1006*25b329d5SDavid du Colombier 	/* Generate and print the PDF output */
1007*25b329d5SDavid du Colombier 	aucBytes = (UCHAR *)szString;
1008*25b329d5SDavid du Colombier 	vFPprintf(pFile, "(");
1009*25b329d5SDavid du Colombier 	for (tCount = 0; tCount < tStringLength ; tCount++) {
1010*25b329d5SDavid du Colombier 		switch (aucBytes[tCount]) {
1011*25b329d5SDavid du Colombier 		case '(':
1012*25b329d5SDavid du Colombier 		case ')':
1013*25b329d5SDavid du Colombier 		case '\\':
1014*25b329d5SDavid du Colombier 			vFPprintf(pFile, "\\%c", szString[tCount]);
1015*25b329d5SDavid du Colombier 			break;
1016*25b329d5SDavid du Colombier 		default:
1017*25b329d5SDavid du Colombier 			if (aucBytes[tCount] < 0x20 ||
1018*25b329d5SDavid du Colombier 			    aucBytes[tCount] == 0x7f ||
1019*25b329d5SDavid du Colombier 			    (aucBytes[tCount] >= 0x81 &&
1020*25b329d5SDavid du Colombier 			     aucBytes[tCount] < 0x8c)) {
1021*25b329d5SDavid du Colombier 				DBG_HEX(aucBytes[tCount]);
1022*25b329d5SDavid du Colombier 				vFPprintf(pFile, " ");
1023*25b329d5SDavid du Colombier 			} else if (aucBytes[tCount] >= 0x80) {
1024*25b329d5SDavid du Colombier 				vFPprintf(pFile, "\\%03o",
1025*25b329d5SDavid du Colombier 						(UINT)aucBytes[tCount]);
1026*25b329d5SDavid du Colombier 			} else {
1027*25b329d5SDavid du Colombier 				vFPprintf(pFile, "%c", szString[tCount]);
1028*25b329d5SDavid du Colombier 			}
1029*25b329d5SDavid du Colombier 			break;
1030*25b329d5SDavid du Colombier 		}
1031*25b329d5SDavid du Colombier 	}
1032*25b329d5SDavid du Colombier 	vFPprintf(pFile, ") Tj\n");
1033*25b329d5SDavid du Colombier 
1034*25b329d5SDavid du Colombier 	/* Undo the superscript/subscript move */
1035*25b329d5SDavid du Colombier 	if (dMove != 0.0) {
1036*25b329d5SDavid du Colombier 		vFPprintf(pFile, "0 Ts\n");
1037*25b329d5SDavid du Colombier 	}
1038*25b329d5SDavid du Colombier } /* end of vPrintPDF */
1039*25b329d5SDavid du Colombier 
1040*25b329d5SDavid du Colombier /*
1041*25b329d5SDavid du Colombier  * vSetColor - move to the specified color
1042*25b329d5SDavid du Colombier  */
1043*25b329d5SDavid du Colombier static void
vSetColor(FILE * pFile,UCHAR ucFontColor)1044*25b329d5SDavid du Colombier vSetColor(FILE *pFile, UCHAR ucFontColor)
1045*25b329d5SDavid du Colombier {
1046*25b329d5SDavid du Colombier 	ULONG	ulTmp, ulRed, ulGreen, ulBlue;
1047*25b329d5SDavid du Colombier 
1048*25b329d5SDavid du Colombier 	ulTmp = ulColor2Color(ucFontColor);
1049*25b329d5SDavid du Colombier 	ulRed   = (ulTmp & 0x0000ff00) >> 8;
1050*25b329d5SDavid du Colombier 	ulGreen = (ulTmp & 0x00ff0000) >> 16;
1051*25b329d5SDavid du Colombier 	ulBlue  = (ulTmp & 0xff000000) >> 24;
1052*25b329d5SDavid du Colombier 	vFPprintf(pFile, "%.3f %.3f %.3f rg\n",
1053*25b329d5SDavid du Colombier 			ulRed / 255.0, ulGreen / 255.0, ulBlue / 255.0);
1054*25b329d5SDavid du Colombier } /* end of vSetColor */
1055*25b329d5SDavid du Colombier 
1056*25b329d5SDavid du Colombier /*
1057*25b329d5SDavid du Colombier  * vMove2NextLinePDF - move to the next line
1058*25b329d5SDavid du Colombier  */
1059*25b329d5SDavid du Colombier void
vMove2NextLinePDF(diagram_type * pDiag,USHORT usFontSize)1060*25b329d5SDavid du Colombier vMove2NextLinePDF(diagram_type *pDiag, USHORT usFontSize)
1061*25b329d5SDavid du Colombier {
1062*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
1063*25b329d5SDavid du Colombier 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1064*25b329d5SDavid du Colombier 
1065*25b329d5SDavid du Colombier 	pDiag->lYtop -= lComputeLeading(usFontSize);
1066*25b329d5SDavid du Colombier } /* end of vMove2NextLinePDF */
1067*25b329d5SDavid du Colombier 
1068*25b329d5SDavid du Colombier /*
1069*25b329d5SDavid du Colombier  * vSubstringPDF - print a sub string
1070*25b329d5SDavid du Colombier  */
1071*25b329d5SDavid du Colombier void
vSubstringPDF(diagram_type * pDiag,char * szString,size_t tStringLength,long lStringWidth,UCHAR ucFontColor,USHORT usFontstyle,drawfile_fontref tFontRef,USHORT usFontSize,USHORT usMaxFontSize)1072*25b329d5SDavid du Colombier vSubstringPDF(diagram_type *pDiag,
1073*25b329d5SDavid du Colombier 	char *szString, size_t tStringLength, long lStringWidth,
1074*25b329d5SDavid du Colombier 	UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
1075*25b329d5SDavid du Colombier 	USHORT usFontSize, USHORT usMaxFontSize)
1076*25b329d5SDavid du Colombier {
1077*25b329d5SDavid du Colombier 	size_t	tFontIndex;
1078*25b329d5SDavid du Colombier 
1079*25b329d5SDavid du Colombier 	fail(pDiag == NULL || szString == NULL);
1080*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
1081*25b329d5SDavid du Colombier 	fail(pDiag->lXleft < 0);
1082*25b329d5SDavid du Colombier 	fail(tStringLength != strlen(szString));
1083*25b329d5SDavid du Colombier 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1084*25b329d5SDavid du Colombier 	fail(usMaxFontSize < MIN_FONT_SIZE || usMaxFontSize > MAX_FONT_SIZE);
1085*25b329d5SDavid du Colombier 	fail(usFontSize > usMaxFontSize);
1086*25b329d5SDavid du Colombier 
1087*25b329d5SDavid du Colombier 	if (szString[0] == '\0' || tStringLength == 0) {
1088*25b329d5SDavid du Colombier 		return;
1089*25b329d5SDavid du Colombier 	}
1090*25b329d5SDavid du Colombier 
1091*25b329d5SDavid du Colombier 	vMoveTo(pDiag, lComputeLeading(usMaxFontSize));
1092*25b329d5SDavid du Colombier 	if (tFontRef != tFontRefCurr || usFontSize != usFontSizeCurr) {
1093*25b329d5SDavid du Colombier 		tFontIndex = tGetFontIndex(tFontRef);
1094*25b329d5SDavid du Colombier 		vFPprintf(pDiag->pOutFile, "/F%u %.1f Tf\n",
1095*25b329d5SDavid du Colombier 			 1 + tFontIndex, (double)usFontSize / 2.0);
1096*25b329d5SDavid du Colombier 		tFontRefCurr = tFontRef;
1097*25b329d5SDavid du Colombier 		usFontSizeCurr = usFontSize;
1098*25b329d5SDavid du Colombier 	}
1099*25b329d5SDavid du Colombier 	if ((int)ucFontColor != iFontColorCurr) {
1100*25b329d5SDavid du Colombier 		vSetColor(pDiag->pOutFile, ucFontColor);
1101*25b329d5SDavid du Colombier 		iFontColorCurr = (int)ucFontColor;
1102*25b329d5SDavid du Colombier 	}
1103*25b329d5SDavid du Colombier 	vPrintPDF(pDiag->pOutFile, szString, tStringLength, usFontstyle);
1104*25b329d5SDavid du Colombier 	pDiag->lXleft += lStringWidth;
1105*25b329d5SDavid du Colombier } /* end of vSubstringPDF */
1106*25b329d5SDavid du Colombier 
1107*25b329d5SDavid du Colombier /*
1108*25b329d5SDavid du Colombier  * Create an start of paragraph by moving the y-top mark
1109*25b329d5SDavid du Colombier  */
1110*25b329d5SDavid du Colombier void
vStartOfParagraphPDF(diagram_type * pDiag,long lBeforeIndentation)1111*25b329d5SDavid du Colombier vStartOfParagraphPDF(diagram_type *pDiag, long lBeforeIndentation)
1112*25b329d5SDavid du Colombier {
1113*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
1114*25b329d5SDavid du Colombier 	fail(lBeforeIndentation < 0);
1115*25b329d5SDavid du Colombier 
1116*25b329d5SDavid du Colombier 	pDiag->lXleft = 0;
1117*25b329d5SDavid du Colombier 	pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
1118*25b329d5SDavid du Colombier } /* end of vStartOfParagraphPDF */
1119*25b329d5SDavid du Colombier 
1120*25b329d5SDavid du Colombier /*
1121*25b329d5SDavid du Colombier  * Create an end of paragraph by moving the y-top mark
1122*25b329d5SDavid du Colombier  */
1123*25b329d5SDavid du Colombier void
vEndOfParagraphPDF(diagram_type * pDiag,USHORT usFontSize,long lAfterIndentation)1124*25b329d5SDavid du Colombier vEndOfParagraphPDF(diagram_type *pDiag,
1125*25b329d5SDavid du Colombier 	USHORT usFontSize, long lAfterIndentation)
1126*25b329d5SDavid du Colombier {
1127*25b329d5SDavid du Colombier 	fail(pDiag == NULL);
1128*25b329d5SDavid du Colombier 	fail(pDiag->pOutFile == NULL);
1129*25b329d5SDavid du Colombier 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
1130*25b329d5SDavid du Colombier 	fail(lAfterIndentation < 0);
1131*25b329d5SDavid du Colombier 
1132*25b329d5SDavid du Colombier 	if (pDiag->lXleft > 0) {
1133*25b329d5SDavid du Colombier 		/* To the start of the line */
1134*25b329d5SDavid du Colombier 		vMove2NextLinePDF(pDiag, usFontSize);
1135*25b329d5SDavid du Colombier 	}
1136*25b329d5SDavid du Colombier 
1137*25b329d5SDavid du Colombier 	pDiag->lXleft = 0;
1138*25b329d5SDavid du Colombier 	pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
1139*25b329d5SDavid du Colombier } /* end of vEndOfParagraphPDF */
1140*25b329d5SDavid du Colombier 
1141*25b329d5SDavid du Colombier /*
1142*25b329d5SDavid du Colombier  * Create an end of page
1143*25b329d5SDavid du Colombier  */
1144*25b329d5SDavid du Colombier void
vEndOfPagePDF(diagram_type * pDiag,BOOL bNewSection)1145*25b329d5SDavid du Colombier vEndOfPagePDF(diagram_type *pDiag, BOOL bNewSection)
1146*25b329d5SDavid du Colombier {
1147*25b329d5SDavid du Colombier 	vMove2NextPage(pDiag, bNewSection);
1148*25b329d5SDavid du Colombier } /* end of vEndOfPagePDF */
1149