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