3 * Copyright (C) 2003-2005 A.J. van Os; Released under GNU GPL
6 * Functions to deal with the Adobe Portable Document Format (pdf)
16 /* Constants for the file positions */
17 #define INITIAL_LOCATION_SIZE 20
18 #define INITIAL_PAGEOBJECT_SIZE 5
20 #define EXTENSION_ARRAY_SIZE 10
22 #define EXTENSION_ARRAY_SIZE 30
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;
43 static int iImageCount
= 0;
45 static int iSectionIndex
= 0;
46 /* Are we on the first page of the section? */
47 static BOOL bFirstInSection
= TRUE
;
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;
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);
66 const char *szPDFname
;
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
[] = {
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",
133 * tGetFontIndex - get the font index
136 tGetFontIndex(drawfile_fontref tFontRef
)
138 const char *szFontname
;
141 /* Get the font name */
142 szFontname
= szGetFontname(tFontRef
);
143 fail(szFontname
== NULL
);
144 if (szFontname
== NULL
) {
148 /* Find the name in the table */
149 for (tIndex
= 0; tIndex
< elementsof(atFontname
); tIndex
++) {
150 if (STRCEQ(atFontname
[tIndex
].szPSname
, szFontname
)) {
158 } /* end of tGetFontIndex */
161 * vSetLocation - store the location of objects
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));
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
192 vFillNextPageObject(void)
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)
211 vFPprintf(FILE *pOutFile
, const char *szFormat
, ...)
215 va_start(tArg
, szFormat
);
216 lFilePosition
+= vfprintf(pOutFile
, szFormat
, tArg
);
218 } /* end of vFPprintf */
221 * vCreateInfoDictionary - create the document information dictionary
224 vCreateInfoDictionary(diagram_type
*pDiag
, int iWordVersion
)
227 const char *szTitle
, *szAuthor
, *szSubject
, *szCreator
;
228 const char *szCreationDate
, *szModDate
;
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
;
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
285 vAddHdrFtr(diagram_type
*pDiag
, const hdrftr_block_type
*pHdrFtrInfo
)
287 output_type
*pStart
, *pPrev
, *pNext
;
290 fail(pHdrFtrInfo
== NULL
);
292 vStartOfParagraphPDF(pDiag
, 0);
293 pStart
= pHdrFtrInfo
->pText
;
294 while (pStart
!= NULL
) {
296 while (pNext
!= NULL
&&
297 (pNext
->tNextFree
!= 1 ||
298 (pNext
->szStorage
[0] != PAR_END
&&
299 pNext
->szStorage
[0] != HARD_RETURN
))) {
300 pNext
= pNext
->pNext
;
303 if (bOutputContainsText(pStart
)) {
304 vAlign2Window(pDiag
, pStart
,
305 lChar2MilliPoints(DEFAULT_SCREEN_WIDTH
),
308 vMove2NextLinePDF(pDiag
, pStart
->usFontSize
);
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
);
322 if (bOutputContainsText(pStart
)) {
324 vAlign2Window(pDiag
, pStart
,
325 lChar2MilliPoints(DEFAULT_SCREEN_WIDTH
),
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
346 vAddHeader(diagram_type
*pDiag
)
348 const hdrftr_block_type
*pHdrInfo
;
349 const hdrftr_block_type
*pFtrInfo
;
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);
373 vAddHdrFtr(pDiag
, pHdrInfo
);
375 DBG_DEC_C(pHdrInfo
->lHeight
!=
376 lPageHeight
- PS_TOP_MARGIN
- pDiag
->lYtop
,
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
387 vAddFooter(diagram_type
*pDiag
)
389 const hdrftr_block_type
*pFtrInfo
;
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);
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
,
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
;
421 } else if (pDiag
->lYtop
< lFooterHeight
+ PS_BOTTOM_MARGIN
/ 2) {
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
;
431 DBG_FLT_C(pDiag
->lYtop
< lFooterHeight
+ PS_BOTTOM_MARGIN
,
432 dDrawUnits2Points(lFooterHeight
+ PS_BOTTOM_MARGIN
- pDiag
->lYtop
));
434 vAddHdrFtr(pDiag
, pFtrInfo
);
436 } /* end of vAddFooter */
439 * vEndPageObject - end the current page object
442 vEndPageObject(FILE *pOutFile
)
446 if (lStreamStart
< 0) {
447 /* There is no current page object */
451 vFPprintf(pOutFile
, "ET\n");
452 lStreamEnd
= lFilePosition
;
453 vFPprintf(pOutFile
, "endstream\n");
454 vFPprintf(pOutFile
, "endobj\n");
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
467 vMove2NextPage(diagram_type
*pDiag
, BOOL bNewSection
)
472 fail(pDiag
->pOutFile
== NULL
);
474 pOutFile
= pDiag
->pOutFile
;
477 /* End the old page object */
478 vEndPageObject(pOutFile
);
481 bFirstInSection
= TRUE
;
484 /* Start the new page object */
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 */
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;
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
524 vMoveTo(diagram_type
*pDiag
, long lLastVerticalMovement
)
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
551 vProloguePDF(diagram_type
*pDiag
,
552 const char *szTask
, const options_type
*pOptions
)
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
;
575 lPageHeight
= lPoints2DrawUnits(pOptions
->iPageHeight
);
577 DBG_DEC(lPageHeight
);
578 if (pOptions
->iPageWidth
== INT_MAX
) {
579 lPageWidth
= LONG_MAX
;
581 lPageWidth
= lPoints2DrawUnits(pOptions
->iPageWidth
);
587 tFontRefCurr
= (drawfile_fontref
)-1;
594 bFirstInSection
= TRUE
;
596 iMaxLocationNumber
= 0;
598 iObjectNumberCurr
= 17;
604 vFPprintf(pOutFile
, "%%PDF-1.3\n");
605 vFPprintf(pOutFile
, "%%%c%c%c%c\n", 0xe2, 0xe3, 0xcf, 0xd3);
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
621 vEpiloguePDF(diagram_type
*pDiag
)
628 fail(pDiag
->pOutFile
== NULL
);
630 pOutFile
= pDiag
->pOutFile
;
633 /* End the old page object */
634 vEndPageObject(pOutFile
);
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");
673 aiPageObject
= xfree(aiPageObject
);
674 alLocation
= xfree(alLocation
);
675 } /* end of vEpiloguePDF */
678 * vPrintPalette - print a pdf color space (palette)
681 vPrintPalette(FILE *pOutFile
, const imagedata_type
*pImg
)
685 fail(pOutFile
== 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");
705 vFPprintf(pOutFile
, " ");
708 vFPprintf(pOutFile
, "> ]\n");
709 } /* end of vPrintPalette */
712 * vImageProloguePDF - perform the image initialization
715 vImageProloguePDF(diagram_type
*pDiag
, const imagedata_type
*pImg
)
720 fail(pDiag
->pOutFile
== NULL
);
723 if (pImg
->iVerSizeScaled
<= 0 || pImg
->iHorSizeScaled
<= 0) {
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
);
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
) {
758 vFPprintf(pOutFile
, "\t/ColorSpace /DeviceGray\n");
761 vFPprintf(pOutFile
, "\t/ColorSpace /DeviceRGB\n");
764 vFPprintf(pOutFile
, "\t/ColorSpace /DeviceCMYK\n");
767 * Adobe-conforming CMYK file
768 * applying workaround for color inversion
771 "\t/Decode [1 0 1 0 1 0 1 0]\n");
775 DBG_DEC(pImg
->iComponents
);
778 vFPprintf(pOutFile
, "\t/BitsPerComponent 8\n");
780 "\t/Filter [ /ASCII85Decode /DCTDecode ]\n");
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
);
792 vFPprintf(pOutFile
, "\t/ColorSpace /DeviceGray\n");
793 vFPprintf(pOutFile
, "\t/BitsPerComponent 8\n");
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");
805 case imagetype_is_dib
:
806 if (pImg
->uiBitsPerComponent
<= 8) {
807 vPrintPalette(pOutFile
, pImg
);
809 vFPprintf(pOutFile
, "\t/ColorSpace /DeviceRGB\n");
811 vFPprintf(pOutFile
, "\t/BitsPerComponent 8\n");
812 vFPprintf(pOutFile
, "\t/Filter /ASCII85Decode\n");
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");
821 vFPprintf(pOutFile
, "ID\n");
822 } /* end of vImageProloguePDF */
825 * vImageEpiloguePDF - clean up after the image
828 vImageEpiloguePDF(diagram_type
*pDiag
)
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");
845 } /* end of vImageEpiloguePDF */
848 * bAddDummyImagePDF - add a dummy image
850 * return TRUE when successful, otherwise FALSE
853 bAddDummyImagePDF(diagram_type
*pDiag
, const imagedata_type
*pImg
)
858 fail(pDiag
->pOutFile
== NULL
);
861 if (pImg
->iVerSizeScaled
<= 0 || pImg
->iHorSizeScaled
<= 0) {
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");
890 } /* end of bAddDummyImagePDF */
893 * vAddFontsPDF - add the font information
896 vAddFontsPDF(diagram_type
*pDiag
)
902 fail(pDiag
->pOutFile
== NULL
);
904 pOutFile
= pDiag
->pOutFile
;
906 /* The font encoding */
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");
914 case encoding_latin_1
:
916 tIndex
< elementsof(iso_8859_1
);
918 vFPprintf(pOutFile
, "%s\n", iso_8859_1
[tIndex
]);
921 case encoding_latin_2
:
923 tIndex
< elementsof(iso_8859_2
);
925 vFPprintf(pOutFile
, "%s\n", iso_8859_2
[tIndex
]);
928 case encoding_cyrillic
:
930 "The combination PDF and Cyrillic is not supported");
934 "The combination PDF and UTF-8 is not supported");
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");
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");
972 } /* end of vAddFontsPDF */
975 * vPrintPDF - print a PDF string
978 vPrintPDF(FILE *pFile
, const char *szString
, size_t tStringLength
,
981 const UCHAR
*aucBytes
;
985 fail(szString
== NULL
);
987 if (szString
== NULL
|| szString
[0] == '\0' || tStringLength
== 0) {
990 DBG_DEC_C(usFontSizeCurr
< MIN_FONT_SIZE
, usFontSizeCurr
);
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
]) {
1014 vFPprintf(pFile
, "\\%c", szString
[tCount
]);
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
]);
1027 vFPprintf(pFile
, "%c", szString
[tCount
]);
1032 vFPprintf(pFile
, ") Tj\n");
1034 /* Undo the superscript/subscript move */
1036 vFPprintf(pFile
, "0 Ts\n");
1038 } /* end of vPrintPDF */
1041 * vSetColor - move to the specified color
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
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
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
)
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) {
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
1111 vStartOfParagraphPDF(diagram_type
*pDiag
, long lBeforeIndentation
)
1113 fail(pDiag
== NULL
);
1114 fail(lBeforeIndentation
< 0);
1117 pDiag
->lYtop
-= lMilliPoints2DrawUnits(lBeforeIndentation
);
1118 } /* end of vStartOfParagraphPDF */
1121 * Create an end of paragraph by moving the y-top mark
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
);
1138 pDiag
->lYtop
-= lMilliPoints2DrawUnits(lAfterIndentation
);
1139 } /* end of vEndOfParagraphPDF */
1142 * Create an end of page
1145 vEndOfPagePDF(diagram_type
*pDiag
, BOOL bNewSection
)
1147 vMove2NextPage(pDiag
, bNewSection
);
1148 } /* end of vEndOfPagePDF */