|
@@ -0,0 +1,1148 @@
|
|
|
+/*
|
|
|
+ * pdf.c
|
|
|
+ * Copyright (C) 2003-2005 A.J. van Os; Released under GNU GPL
|
|
|
+ *
|
|
|
+ * Description:
|
|
|
+ * Functions to deal with the Adobe Portable Document Format (pdf)
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+#include <stdarg.h>
|
|
|
+#include <string.h>
|
|
|
+#include "version.h"
|
|
|
+#include "antiword.h"
|
|
|
+
|
|
|
+
|
|
|
+/* Constants for the file positions */
|
|
|
+#define INITIAL_LOCATION_SIZE 20
|
|
|
+#define INITIAL_PAGEOBJECT_SIZE 5
|
|
|
+#if defined(DEBUG)
|
|
|
+#define EXTENSION_ARRAY_SIZE 10
|
|
|
+#else
|
|
|
+#define EXTENSION_ARRAY_SIZE 30
|
|
|
+#endif /* DEBUG */
|
|
|
+
|
|
|
+/* The character set */
|
|
|
+static encoding_type eEncoding = encoding_neutral;
|
|
|
+/* Current creator for a PDF header */
|
|
|
+static const char *szProducer = NULL;
|
|
|
+/* The height and width of a PDF page (in DrawUnits) */
|
|
|
+static long lPageHeight = LONG_MAX;
|
|
|
+static long lPageWidth = LONG_MAX;
|
|
|
+/* The height of the footer on the current page (in DrawUnits) */
|
|
|
+static long lFooterHeight = 0;
|
|
|
+/* Inside a footer (to prevent an infinite loop when the footer is too big) */
|
|
|
+static BOOL bInFtrSpace = FALSE;
|
|
|
+/* Current font information */
|
|
|
+static drawfile_fontref tFontRefCurr = (drawfile_fontref)-1;
|
|
|
+static USHORT usFontSizeCurr = 0;
|
|
|
+static int iFontColorCurr = -1;
|
|
|
+/* Current vertical position information */
|
|
|
+static long lYtopCurr = -1;
|
|
|
+/* Image counter */
|
|
|
+static int iImageCount = 0;
|
|
|
+/* Section index */
|
|
|
+static int iSectionIndex = 0;
|
|
|
+/* Are we on the first page of the section? */
|
|
|
+static BOOL bFirstInSection = TRUE;
|
|
|
+/* File positions */
|
|
|
+static long lFilePosition = 0;
|
|
|
+static long *alLocation = NULL;
|
|
|
+static size_t tLocations = 0;
|
|
|
+static int iMaxLocationNumber = 0;
|
|
|
+/* File position at the start of a page */
|
|
|
+static long lStreamStart = -1;
|
|
|
+/* Page objects */
|
|
|
+static int *aiPageObject = NULL;
|
|
|
+static int iPageCount = 0;
|
|
|
+static size_t tMaxPageObjects = 0;
|
|
|
+/* Current object number */
|
|
|
+/* 1 = root; 2 = info; 3 = pages; 4 = encoding; 5-16 = fonts; 17 = resources */
|
|
|
+static int iObjectNumberCurr = 17;
|
|
|
+
|
|
|
+static void vMoveTo(diagram_type *, long);
|
|
|
+
|
|
|
+static const struct {
|
|
|
+ const char *szPDFname;
|
|
|
+ const char *szPSname;
|
|
|
+} atFontname[] = {
|
|
|
+ { "Courier", FONT_MONOSPACED_PLAIN },
|
|
|
+ { "Courier-Bold", FONT_MONOSPACED_BOLD },
|
|
|
+ { "Courier-Oblique", FONT_MONOSPACED_ITALIC },
|
|
|
+ { "Courier-BoldOblique", FONT_MONOSPACED_BOLDITALIC },
|
|
|
+ { "Helvetica", FONT_SANS_SERIF_PLAIN },
|
|
|
+ { "Helvetica-Bold", FONT_SANS_SERIF_BOLD },
|
|
|
+ { "Helvetica-Oblique", FONT_SANS_SERIF_ITALIC },
|
|
|
+ { "Helvetica-BoldOblique", FONT_SANS_SERIF_BOLDITALIC },
|
|
|
+ { "Times-Roman", FONT_SERIF_PLAIN },
|
|
|
+ { "Times-Bold", FONT_SERIF_BOLD },
|
|
|
+ { "Times-Italic", FONT_SERIF_ITALIC },
|
|
|
+ { "Times-BoldItalic", FONT_SERIF_BOLDITALIC },
|
|
|
+};
|
|
|
+
|
|
|
+static const char *iso_8859_1[] = {
|
|
|
+"128 /Euro",
|
|
|
+"140 /ellipsis /trademark /perthousand /bullet",
|
|
|
+" /quoteleft /quoteright /guilsinglleft /guilsinglright",
|
|
|
+" /quotedblleft /quotedblright /quotedblbase /endash /emdash",
|
|
|
+" /minus /OE /oe /dagger /daggerdbl /fi /fl",
|
|
|
+"160 /space /exclamdown /cent /sterling /currency",
|
|
|
+" /yen /brokenbar /section /dieresis /copyright",
|
|
|
+" /ordfeminine /guillemotleft /logicalnot /hyphen /registered",
|
|
|
+" /macron /degree /plusminus /twosuperior /threesuperior",
|
|
|
+" /acute /mu /paragraph /periodcentered /cedilla",
|
|
|
+" /onesuperior /ordmasculine /guillemotright /onequarter",
|
|
|
+" /onehalf /threequarters /questiondown /Agrave /Aacute",
|
|
|
+" /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla",
|
|
|
+" /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute",
|
|
|
+" /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute",
|
|
|
+" /Ocircumflex /Otilde /Odieresis /multiply /Oslash",
|
|
|
+" /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn",
|
|
|
+" /germandbls /agrave /aacute /acircumflex /atilde",
|
|
|
+" /adieresis /aring /ae /ccedilla /egrave /eacute",
|
|
|
+" /ecircumflex /edieresis /igrave /iacute /icircumflex",
|
|
|
+" /idieresis /eth /ntilde /ograve /oacute /ocircumflex",
|
|
|
+" /otilde /odieresis /divide /oslash /ugrave /uacute",
|
|
|
+" /ucircumflex /udieresis /yacute /thorn /ydieresis",
|
|
|
+};
|
|
|
+
|
|
|
+static const char *iso_8859_2[] = {
|
|
|
+"160 /space /Aogonek /breve /Lslash /currency /Lcaron",
|
|
|
+" /Sacute /section /dieresis /Scaron /Scommaaccent",
|
|
|
+" /Tcaron /Zacute /hyphen /Zcaron /Zdotaccent /degree",
|
|
|
+" /aogonek /ogonek /lslash /acute /lcaron /sacute",
|
|
|
+" /caron /cedilla /scaron /scommaaccent /tcaron",
|
|
|
+" /zacute /hungarumlaut /zcaron /zdotaccent /Racute",
|
|
|
+" /Aacute /Acircumflex /Abreve /Adieresis /Lacute",
|
|
|
+" /Cacute /Ccedilla /Ccaron /Eacute /Eogonek",
|
|
|
+" /Edieresis /Ecaron /Iacute /Icircumflex /Dcaron",
|
|
|
+" /.notdef /Nacute /Ncaron /Oacute /Ocircumflex",
|
|
|
+" /Ohungarumlaut /Odieresis /multiply /Rcaron /Uring",
|
|
|
+" /Uacute /Uhungarumlaut /Udieresis /Yacute /Tcommaaccent",
|
|
|
+" /germandbls /racute /aacute /acircumflex /abreve",
|
|
|
+" /adieresis /lacute /cacute /ccedilla /ccaron /eacute",
|
|
|
+" /eogonek /edieresis /ecaron /iacute /icircumflex",
|
|
|
+" /dcaron /.notdef /nacute /ncaron /oacute /ocircumflex",
|
|
|
+" /ohungarumlaut /odieresis /divide /rcaron /uring",
|
|
|
+" /uacute /uhungarumlaut /udieresis /yacute /tcommaaccent",
|
|
|
+" /dotaccent",
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * tGetFontIndex - get the font index
|
|
|
+ */
|
|
|
+static size_t
|
|
|
+tGetFontIndex(drawfile_fontref tFontRef)
|
|
|
+{
|
|
|
+ const char *szFontname;
|
|
|
+ size_t tIndex;
|
|
|
+
|
|
|
+ /* Get the font name */
|
|
|
+ szFontname = szGetFontname(tFontRef);
|
|
|
+ fail(szFontname == NULL);
|
|
|
+ if (szFontname == NULL) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Find the name in the table */
|
|
|
+ for (tIndex = 0; tIndex < elementsof(atFontname); tIndex++) {
|
|
|
+ if (STRCEQ(atFontname[tIndex].szPSname, szFontname)) {
|
|
|
+ return tIndex;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* Not found */
|
|
|
+ DBG_DEC(tFontRef);
|
|
|
+ DBG_MSG(szFontname);
|
|
|
+ return 0;
|
|
|
+} /* end of tGetFontIndex */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vSetLocation - store the location of objects
|
|
|
+ */
|
|
|
+static void
|
|
|
+vSetLocation(int iLocationNumber)
|
|
|
+{
|
|
|
+ fail(iLocationNumber <= 0);
|
|
|
+
|
|
|
+ if ((size_t)iLocationNumber >= tLocations) {
|
|
|
+ /* Extend and set to zero */
|
|
|
+ tLocations += EXTENSION_ARRAY_SIZE;
|
|
|
+ alLocation = xrealloc(alLocation, tLocations * sizeof(long));
|
|
|
+ memset(alLocation + tLocations - EXTENSION_ARRAY_SIZE,
|
|
|
+ 0,
|
|
|
+ EXTENSION_ARRAY_SIZE * sizeof(long));
|
|
|
+ DBG_DEC(tLocations);
|
|
|
+ }
|
|
|
+ if (iLocationNumber > iMaxLocationNumber) {
|
|
|
+ iMaxLocationNumber = iLocationNumber;
|
|
|
+ }
|
|
|
+
|
|
|
+ DBG_DEC_C((size_t)iLocationNumber >= tLocations, iLocationNumber);
|
|
|
+ DBG_DEC_C((size_t)iLocationNumber >= tLocations, tLocations);
|
|
|
+ fail((size_t)iLocationNumber >= tLocations);
|
|
|
+
|
|
|
+ alLocation[iLocationNumber] = lFilePosition;
|
|
|
+} /* end of vSetLocation */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vFillNextPageObject - fil the next page object with the current object number
|
|
|
+ */
|
|
|
+static void
|
|
|
+vFillNextPageObject(void)
|
|
|
+{
|
|
|
+ iPageCount++;
|
|
|
+ if ((size_t)iPageCount >= tMaxPageObjects) {
|
|
|
+ /* Extend the array */
|
|
|
+ tMaxPageObjects += EXTENSION_ARRAY_SIZE;
|
|
|
+ aiPageObject = xrealloc(aiPageObject,
|
|
|
+ tMaxPageObjects * sizeof(int));
|
|
|
+ DBG_DEC(tMaxPageObjects);
|
|
|
+ }
|
|
|
+ aiPageObject[iPageCount] = iObjectNumberCurr;
|
|
|
+} /* end of vFillNextPageObject */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vFPprintf - printf and update the fileposition
|
|
|
+ *
|
|
|
+ * called with arguments like fprintf(3)
|
|
|
+ */
|
|
|
+static void
|
|
|
+vFPprintf(FILE *pOutFile, const char *szFormat, ...)
|
|
|
+{
|
|
|
+ va_list tArg;
|
|
|
+
|
|
|
+ va_start(tArg, szFormat);
|
|
|
+ lFilePosition += vfprintf(pOutFile, szFormat, tArg);
|
|
|
+ va_end(tArg);
|
|
|
+} /* end of vFPprintf */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vCreateInfoDictionary - create the document information dictionary
|
|
|
+ */
|
|
|
+void
|
|
|
+vCreateInfoDictionary(diagram_type *pDiag, int iWordVersion)
|
|
|
+{
|
|
|
+ FILE *pOutFile;
|
|
|
+ const char *szTitle, *szAuthor, *szSubject, *szCreator;
|
|
|
+ const char *szCreationDate, *szModDate;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+ fail(iWordVersion < 0);
|
|
|
+ fail(szProducer == NULL || szProducer[0] == '\0');
|
|
|
+
|
|
|
+ szTitle = szGetTitle();
|
|
|
+ szAuthor = szGetAuthor();
|
|
|
+ szSubject = szGetSubject();
|
|
|
+ szCreationDate = szGetCreationDate();
|
|
|
+ szModDate = szGetModDate();
|
|
|
+
|
|
|
+ switch (iWordVersion) {
|
|
|
+ case 0: szCreator = "Word for DOS"; break;
|
|
|
+ case 1: szCreator = "WinWord 1.x"; break;
|
|
|
+ case 2: szCreator = "WinWord 2.0"; break;
|
|
|
+ case 4: szCreator = "MacWord 4"; break;
|
|
|
+ case 5: szCreator = "MacWord 5"; break;
|
|
|
+ case 6: szCreator = "Word 6"; break;
|
|
|
+ case 7: szCreator = "Word 7/95"; break;
|
|
|
+ case 8: szCreator = "Word 97 or later"; break;
|
|
|
+ default: szCreator = NULL; break;
|
|
|
+ }
|
|
|
+
|
|
|
+ pOutFile = pDiag->pOutFile;
|
|
|
+
|
|
|
+ vSetLocation(2);
|
|
|
+ vFPprintf(pOutFile, "2 0 obj\n");
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ if (szTitle != NULL && szTitle[0] != '\0') {
|
|
|
+ vFPprintf(pOutFile, "/Title (%s)\n", szTitle);
|
|
|
+ }
|
|
|
+ if (szAuthor != NULL && szAuthor[0] != '\0') {
|
|
|
+ vFPprintf(pOutFile, "/Author (%s)\n", szAuthor);
|
|
|
+ }
|
|
|
+ if (szSubject != NULL && szSubject[0] != '\0') {
|
|
|
+ vFPprintf(pOutFile, "/Subject (%s)\n", szSubject);
|
|
|
+ }
|
|
|
+ if (szCreator != NULL && szCreator[0] != '\0') {
|
|
|
+ vFPprintf(pOutFile, "/Creator (%s)\n", szCreator);
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "/Producer (%s %s)\n", szProducer, VERSIONSTRING);
|
|
|
+ if (szCreationDate != NULL && szCreationDate[0] != '\0') {
|
|
|
+ vFPprintf(pOutFile, "/CreationDate (%s)\n", szCreationDate);
|
|
|
+ }
|
|
|
+ if (szModDate != NULL && szModDate[0] != '\0') {
|
|
|
+ vFPprintf(pOutFile, "/ModDate (%s)\n", szModDate);
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+} /* end of vCreateInfoDictionary */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vAddHdrFtr - add a header or footer
|
|
|
+ */
|
|
|
+static void
|
|
|
+vAddHdrFtr(diagram_type *pDiag, const hdrftr_block_type *pHdrFtrInfo)
|
|
|
+{
|
|
|
+ output_type *pStart, *pPrev, *pNext;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pHdrFtrInfo == NULL);
|
|
|
+
|
|
|
+ vStartOfParagraphPDF(pDiag, 0);
|
|
|
+ pStart = pHdrFtrInfo->pText;
|
|
|
+ while (pStart != NULL) {
|
|
|
+ pNext = pStart;
|
|
|
+ while (pNext != NULL &&
|
|
|
+ (pNext->tNextFree != 1 ||
|
|
|
+ (pNext->szStorage[0] != PAR_END &&
|
|
|
+ pNext->szStorage[0] != HARD_RETURN))) {
|
|
|
+ pNext = pNext->pNext;
|
|
|
+ }
|
|
|
+ if (pNext == NULL) {
|
|
|
+ if (bOutputContainsText(pStart)) {
|
|
|
+ vAlign2Window(pDiag, pStart,
|
|
|
+ lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
|
|
|
+ ALIGNMENT_LEFT);
|
|
|
+ } else {
|
|
|
+ vMove2NextLinePDF(pDiag, pStart->usFontSize);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ fail(pNext->tNextFree != 1);
|
|
|
+ fail(pNext->szStorage[0] != PAR_END &&
|
|
|
+ pNext->szStorage[0] != HARD_RETURN);
|
|
|
+
|
|
|
+ if (pStart != pNext) {
|
|
|
+ /* There is something to print */
|
|
|
+ pPrev = pNext->pPrev;
|
|
|
+ fail(pPrev->pNext != pNext);
|
|
|
+ /* Cut the chain */
|
|
|
+ pPrev->pNext = NULL;
|
|
|
+ if (bOutputContainsText(pStart)) {
|
|
|
+ /* Print it */
|
|
|
+ vAlign2Window(pDiag, pStart,
|
|
|
+ lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
|
|
|
+ ALIGNMENT_LEFT);
|
|
|
+ } else {
|
|
|
+ /* Just an empty line */
|
|
|
+ vMove2NextLinePDF(pDiag, pStart->usFontSize);
|
|
|
+ }
|
|
|
+ /* Repair the chain */
|
|
|
+ pPrev->pNext = pNext;
|
|
|
+ }
|
|
|
+ if (pNext->szStorage[0] == PAR_END) {
|
|
|
+ vEndOfParagraphPDF(pDiag, pNext->usFontSize,
|
|
|
+ (long)pNext->usFontSize * 200);
|
|
|
+ }
|
|
|
+ pStart = pNext->pNext;
|
|
|
+ }
|
|
|
+} /* end of vAddHdrFtr */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vAddHeader - add a page header
|
|
|
+ */
|
|
|
+static void
|
|
|
+vAddHeader(diagram_type *pDiag)
|
|
|
+{
|
|
|
+ const hdrftr_block_type *pHdrInfo;
|
|
|
+ const hdrftr_block_type *pFtrInfo;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+
|
|
|
+ NO_DBG_MSG("vAddHeader");
|
|
|
+
|
|
|
+ pHdrInfo = pGetHdrFtrInfo(iSectionIndex, TRUE,
|
|
|
+ odd(iPageCount), bFirstInSection);
|
|
|
+ pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
|
|
|
+ odd(iPageCount), bFirstInSection);
|
|
|
+ /* Set the height of the footer of this page */
|
|
|
+ lFooterHeight = pFtrInfo == NULL ? 0 : pFtrInfo->lHeight;
|
|
|
+ fail(lFooterHeight < 0);
|
|
|
+
|
|
|
+ if (pHdrInfo == NULL ||
|
|
|
+ pHdrInfo->pText == NULL ||
|
|
|
+ pHdrInfo->lHeight <= 0) {
|
|
|
+ fail(pHdrInfo != NULL && pHdrInfo->lHeight < 0);
|
|
|
+ fail(pHdrInfo != NULL &&
|
|
|
+ pHdrInfo->pText != NULL &&
|
|
|
+ pHdrInfo->lHeight == 0);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ vAddHdrFtr(pDiag, pHdrInfo);
|
|
|
+
|
|
|
+ DBG_DEC_C(pHdrInfo->lHeight !=
|
|
|
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
|
|
|
+ pHdrInfo->lHeight);
|
|
|
+ DBG_DEC_C(pHdrInfo->lHeight !=
|
|
|
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
|
|
|
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop);
|
|
|
+} /* end of vAddHeader */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vAddFooter - add a page footer
|
|
|
+ */
|
|
|
+static void
|
|
|
+vAddFooter(diagram_type *pDiag)
|
|
|
+{
|
|
|
+ const hdrftr_block_type *pFtrInfo;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+
|
|
|
+ NO_DBG_MSG("vAddFooter");
|
|
|
+
|
|
|
+ pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
|
|
|
+ odd(iPageCount), bFirstInSection);
|
|
|
+ bFirstInSection = FALSE;
|
|
|
+ if (pFtrInfo == NULL ||
|
|
|
+ pFtrInfo->pText == NULL ||
|
|
|
+ pFtrInfo->lHeight <= 0) {
|
|
|
+ fail(pFtrInfo != NULL && pFtrInfo->lHeight < 0);
|
|
|
+ fail(pFtrInfo != NULL &&
|
|
|
+ pFtrInfo->pText != NULL &&
|
|
|
+ pFtrInfo->lHeight == 0);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ bInFtrSpace = TRUE;
|
|
|
+
|
|
|
+ DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, pFtrInfo->lHeight);
|
|
|
+ DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, lFooterHeight);
|
|
|
+ DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
|
|
|
+ pDiag->lYtop);
|
|
|
+ DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
|
|
|
+ lFooterHeight + PS_BOTTOM_MARGIN);
|
|
|
+
|
|
|
+ if (pDiag->lYtop > lFooterHeight + PS_BOTTOM_MARGIN) {
|
|
|
+ /* Move down to the start of the footer */
|
|
|
+ pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
|
|
|
+ vMoveTo(pDiag, 0);
|
|
|
+ } else if (pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN / 2) {
|
|
|
+ DBG_FIXME();
|
|
|
+ /*
|
|
|
+ * Move up to the start of the footer, to prevent moving
|
|
|
+ * of the bottom edge of the paper
|
|
|
+ */
|
|
|
+ pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
|
|
|
+ vMoveTo(pDiag, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ DBG_FLT_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
|
|
|
+ dDrawUnits2Points(lFooterHeight + PS_BOTTOM_MARGIN - pDiag->lYtop));
|
|
|
+
|
|
|
+ vAddHdrFtr(pDiag, pFtrInfo);
|
|
|
+ bInFtrSpace = FALSE;
|
|
|
+} /* end of vAddFooter */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vEndPageObject - end the current page object
|
|
|
+ */
|
|
|
+static void
|
|
|
+vEndPageObject(FILE *pOutFile)
|
|
|
+{
|
|
|
+ long lStreamEnd;
|
|
|
+
|
|
|
+ if (lStreamStart < 0) {
|
|
|
+ /* There is no current page object */
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "ET\n");
|
|
|
+ lStreamEnd = lFilePosition;
|
|
|
+ vFPprintf(pOutFile, "endstream\n");
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+
|
|
|
+ iObjectNumberCurr++;
|
|
|
+ vSetLocation(iObjectNumberCurr);
|
|
|
+ vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
|
|
|
+ vFPprintf(pOutFile, "%lu\n", lStreamEnd - lStreamStart);
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+} /* end of vEndPageObject */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vMove2NextPage - move to the start of the next page
|
|
|
+ */
|
|
|
+static void
|
|
|
+vMove2NextPage(diagram_type *pDiag, BOOL bNewSection)
|
|
|
+{
|
|
|
+ FILE *pOutFile;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+
|
|
|
+ pOutFile = pDiag->pOutFile;
|
|
|
+
|
|
|
+ vAddFooter(pDiag);
|
|
|
+ /* End the old page object */
|
|
|
+ vEndPageObject(pOutFile);
|
|
|
+ if (bNewSection) {
|
|
|
+ iSectionIndex++;
|
|
|
+ bFirstInSection = TRUE;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Start the new page object */
|
|
|
+ iObjectNumberCurr++;
|
|
|
+ vSetLocation(iObjectNumberCurr);
|
|
|
+ vFillNextPageObject();
|
|
|
+ vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ vFPprintf(pOutFile, "/Type /Page\n");
|
|
|
+ vFPprintf(pOutFile, "/Parent 3 0 R\n");
|
|
|
+ vFPprintf(pOutFile, "/Resources 17 0 R\n");
|
|
|
+ vFPprintf(pOutFile, "/Contents %d 0 R\n", iObjectNumberCurr + 1);
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+
|
|
|
+ /* Start the new text object */
|
|
|
+ iObjectNumberCurr++;
|
|
|
+ vSetLocation(iObjectNumberCurr);
|
|
|
+ vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ vFPprintf(pOutFile, "/Length %d 0 R\n", iObjectNumberCurr + 1);
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+ vFPprintf(pOutFile, "stream\n");
|
|
|
+ lStreamStart = lFilePosition;
|
|
|
+ vFPprintf(pOutFile, "BT\n");
|
|
|
+
|
|
|
+ /* Set variables to their start of page values */
|
|
|
+ pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
|
|
|
+ tFontRefCurr = (drawfile_fontref)-1;
|
|
|
+ usFontSizeCurr = 0;
|
|
|
+ iFontColorCurr = -1;
|
|
|
+ lYtopCurr = -1;
|
|
|
+ vAddHeader(pDiag);
|
|
|
+} /* end of vMove2NextPage */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vMoveTo - move to the specified X,Y coordinates
|
|
|
+ *
|
|
|
+ * Move the current position of the specified diagram to its X,Y coordinates,
|
|
|
+ * start on a new page if needed
|
|
|
+ */
|
|
|
+static void
|
|
|
+vMoveTo(diagram_type *pDiag, long lLastVerticalMovement)
|
|
|
+{
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+
|
|
|
+ if (pDiag->lYtop <= lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace) {
|
|
|
+ vMove2NextPage(pDiag, FALSE);
|
|
|
+ /* Repeat the last vertical movement on the new page */
|
|
|
+ pDiag->lYtop -= lLastVerticalMovement;
|
|
|
+ }
|
|
|
+
|
|
|
+ fail(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace);
|
|
|
+ DBG_DEC_C(pDiag->lYtop < PS_BOTTOM_MARGIN, pDiag->lYtop);
|
|
|
+ fail(pDiag->lYtop < PS_BOTTOM_MARGIN / 3);
|
|
|
+
|
|
|
+ if (pDiag->lYtop != lYtopCurr) {
|
|
|
+ vFPprintf(pDiag->pOutFile, "1 0 0 1 %.2f %.2f Tm\n",
|
|
|
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
|
|
|
+ dDrawUnits2Points(pDiag->lYtop));
|
|
|
+ lYtopCurr = pDiag->lYtop;
|
|
|
+ }
|
|
|
+} /* end of vMoveTo */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vProloguePDF - set options and perform the PDF initialization
|
|
|
+ */
|
|
|
+void
|
|
|
+vProloguePDF(diagram_type *pDiag,
|
|
|
+ const char *szTask, const options_type *pOptions)
|
|
|
+{
|
|
|
+ FILE *pOutFile;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+ fail(pOptions == NULL);
|
|
|
+
|
|
|
+ pOutFile = pDiag->pOutFile;
|
|
|
+
|
|
|
+ eEncoding = pOptions->eEncoding;
|
|
|
+
|
|
|
+ /* Create an empty location array */
|
|
|
+ tLocations = INITIAL_LOCATION_SIZE;
|
|
|
+ alLocation = xcalloc(tLocations, sizeof(long));
|
|
|
+
|
|
|
+ /* Create an empty pageobject array */
|
|
|
+ tMaxPageObjects = INITIAL_PAGEOBJECT_SIZE;
|
|
|
+ aiPageObject = xcalloc(tMaxPageObjects, sizeof(int));
|
|
|
+
|
|
|
+ if (pOptions->iPageHeight == INT_MAX) {
|
|
|
+ lPageHeight = LONG_MAX;
|
|
|
+ } else {
|
|
|
+ lPageHeight = lPoints2DrawUnits(pOptions->iPageHeight);
|
|
|
+ }
|
|
|
+ DBG_DEC(lPageHeight);
|
|
|
+ if (pOptions->iPageWidth == INT_MAX) {
|
|
|
+ lPageWidth = LONG_MAX;
|
|
|
+ } else {
|
|
|
+ lPageWidth = lPoints2DrawUnits(pOptions->iPageWidth);
|
|
|
+ }
|
|
|
+ DBG_DEC(lPageWidth);
|
|
|
+ lFooterHeight = 0;
|
|
|
+ bInFtrSpace = FALSE;
|
|
|
+
|
|
|
+ tFontRefCurr = (drawfile_fontref)-1;
|
|
|
+ usFontSizeCurr = 0;
|
|
|
+ iFontColorCurr = -1;
|
|
|
+ lYtopCurr = -1;
|
|
|
+ iPageCount = 0;
|
|
|
+ iImageCount = 0;
|
|
|
+ iSectionIndex = 0;
|
|
|
+ bFirstInSection = TRUE;
|
|
|
+ lFilePosition = 0;
|
|
|
+ iMaxLocationNumber = 0;
|
|
|
+ lStreamStart = -1;
|
|
|
+ iObjectNumberCurr = 17;
|
|
|
+ pDiag->lXleft = 0;
|
|
|
+ pDiag->lYtop = 0;
|
|
|
+
|
|
|
+ szProducer = szTask;
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "%%PDF-1.3\n");
|
|
|
+ vFPprintf(pOutFile, "%%%c%c%c%c\n", 0xe2, 0xe3, 0xcf, 0xd3);
|
|
|
+
|
|
|
+ /* Root catalog */
|
|
|
+ vSetLocation(1);
|
|
|
+ vFPprintf(pOutFile, "1 0 obj\n");
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ vFPprintf(pOutFile, "/Type /Catalog\n");
|
|
|
+ vFPprintf(pOutFile, "/Pages 3 0 R\n");
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+} /* end of vProloguePDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vEpiloguePDF - clean up after everything is done
|
|
|
+ */
|
|
|
+void
|
|
|
+vEpiloguePDF(diagram_type *pDiag)
|
|
|
+{
|
|
|
+ FILE *pOutFile;
|
|
|
+ long lXref;
|
|
|
+ int iIndex;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+
|
|
|
+ pOutFile = pDiag->pOutFile;
|
|
|
+
|
|
|
+ vAddFooter(pDiag);
|
|
|
+ /* End the old page object */
|
|
|
+ vEndPageObject(pOutFile);
|
|
|
+
|
|
|
+ vSetLocation(3);
|
|
|
+ vFPprintf(pOutFile, "3 0 obj\n");
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ vFPprintf(pOutFile, "/Type /Pages\n");
|
|
|
+ vFPprintf(pOutFile, "/Count %d\n", iPageCount);
|
|
|
+ vFPprintf(pOutFile, "/MediaBox [ 0 0 %.0f %.0f ]\n",
|
|
|
+ dDrawUnits2Points(lPageWidth),
|
|
|
+ dDrawUnits2Points(lPageHeight));
|
|
|
+ vFPprintf(pOutFile, "/Kids [ ");
|
|
|
+ for (iIndex = 1; iIndex <= iPageCount; iIndex++) {
|
|
|
+ vFPprintf(pOutFile, "\t%d 0 R\n", aiPageObject[iIndex]);
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "]\n");
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+
|
|
|
+ lXref = lFilePosition;
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "xref\n");
|
|
|
+ vFPprintf(pOutFile, "0 %d\n", iMaxLocationNumber + 1);
|
|
|
+ vFPprintf(pOutFile, "0000000000 65535 f \n");
|
|
|
+ for (iIndex = 1; iIndex <= iMaxLocationNumber; iIndex++) {
|
|
|
+ vFPprintf(pOutFile, "%.10ld 00000 n \n", alLocation[iIndex]);
|
|
|
+ }
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "trailer\n");
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ vFPprintf(pOutFile, "/Size %d\n", iMaxLocationNumber + 1);
|
|
|
+ vFPprintf(pOutFile, "/Root 1 0 R\n");
|
|
|
+ vFPprintf(pOutFile, "/Info 2 0 R\n");
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "startxref\n");
|
|
|
+ vFPprintf(pOutFile, "%ld\n", lXref);
|
|
|
+ vFPprintf(pOutFile, "%%%%EOF\n");
|
|
|
+
|
|
|
+ szProducer = NULL;
|
|
|
+ aiPageObject = xfree(aiPageObject);
|
|
|
+ alLocation = xfree(alLocation);
|
|
|
+} /* end of vEpiloguePDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vPrintPalette - print a pdf color space (palette)
|
|
|
+ */
|
|
|
+static void
|
|
|
+vPrintPalette(FILE *pOutFile, const imagedata_type *pImg)
|
|
|
+{
|
|
|
+ int iIndex;
|
|
|
+
|
|
|
+ fail(pOutFile == NULL);
|
|
|
+ fail(pImg == NULL);
|
|
|
+ fail(pImg->iColorsUsed < 2);
|
|
|
+ fail(pImg->iColorsUsed > 256);
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "\t/ColorSpace [ /Indexed\n");
|
|
|
+ vFPprintf(pOutFile, "\t/Device%s %d\n",
|
|
|
+ pImg->bColorImage ? "RGB" : "Gray", pImg->iColorsUsed - 1);
|
|
|
+ vFPprintf(pOutFile, "<");
|
|
|
+ for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
|
|
|
+ vFPprintf(pOutFile, "%02x",
|
|
|
+ (unsigned int)pImg->aucPalette[iIndex][0]);
|
|
|
+ if (pImg->bColorImage) {
|
|
|
+ vFPprintf(pOutFile, "%02x%02x",
|
|
|
+ (unsigned int)pImg->aucPalette[iIndex][1],
|
|
|
+ (unsigned int)pImg->aucPalette[iIndex][2]);
|
|
|
+ }
|
|
|
+ if (iIndex % 8 == 7) {
|
|
|
+ vFPprintf(pOutFile, "\n");
|
|
|
+ } else {
|
|
|
+ vFPprintf(pOutFile, " ");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "> ]\n");
|
|
|
+} /* end of vPrintPalette */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vImageProloguePDF - perform the image initialization
|
|
|
+ */
|
|
|
+void
|
|
|
+vImageProloguePDF(diagram_type *pDiag, const imagedata_type *pImg)
|
|
|
+{
|
|
|
+ FILE *pOutFile;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+ fail(pImg == NULL);
|
|
|
+
|
|
|
+ if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ iImageCount++;
|
|
|
+
|
|
|
+ DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
|
|
|
+
|
|
|
+ pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
|
|
|
+ vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
|
|
|
+
|
|
|
+ pOutFile = pDiag->pOutFile;
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "ET\n");
|
|
|
+ vFPprintf(pOutFile, "q %% Image %03d\n", iImageCount);
|
|
|
+ if (pImg->eImageType == imagetype_is_dib) {
|
|
|
+ /* Scanning from left to right and bottom to top */
|
|
|
+ vFPprintf(pOutFile, "%d 0 0 %d %.2f %.2f cm\n",
|
|
|
+ pImg->iHorSizeScaled, -pImg->iVerSizeScaled,
|
|
|
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
|
|
|
+ dDrawUnits2Points(pDiag->lYtop) + pImg->iVerSizeScaled);
|
|
|
+ } else {
|
|
|
+ /* Scanning from left to right and top to bottom */
|
|
|
+ vFPprintf(pOutFile, "%d 0 0 %d %.2f %.2f cm\n",
|
|
|
+ pImg->iHorSizeScaled, pImg->iVerSizeScaled,
|
|
|
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
|
|
|
+ dDrawUnits2Points(pDiag->lYtop));
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "BI\n");
|
|
|
+ vFPprintf(pOutFile, "\t/Width %d\n", pImg->iWidth);
|
|
|
+ vFPprintf(pOutFile, "\t/Height %d\n", pImg->iHeight);
|
|
|
+ switch (pImg->eImageType) {
|
|
|
+ case imagetype_is_jpeg:
|
|
|
+ switch (pImg->iComponents) {
|
|
|
+ case 1:
|
|
|
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceGray\n");
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceCMYK\n");
|
|
|
+ if (pImg->bAdobe) {
|
|
|
+ /*
|
|
|
+ * Adobe-conforming CMYK file
|
|
|
+ * applying workaround for color inversion
|
|
|
+ */
|
|
|
+ vFPprintf(pOutFile,
|
|
|
+ "\t/Decode [1 0 1 0 1 0 1 0]\n");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ DBG_DEC(pImg->iComponents);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
|
|
|
+ vFPprintf(pOutFile,
|
|
|
+ "\t/Filter [ /ASCII85Decode /DCTDecode ]\n");
|
|
|
+ break;
|
|
|
+ case imagetype_is_png:
|
|
|
+ if (pImg->iComponents == 3 || pImg->iComponents == 4) {
|
|
|
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
|
|
|
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
|
|
|
+ } else if (pImg->iColorsUsed > 0) {
|
|
|
+ vPrintPalette(pOutFile, pImg);
|
|
|
+ fail(pImg->uiBitsPerComponent > 8);
|
|
|
+ vFPprintf(pOutFile, "\t/BitsPerComponent %u\n",
|
|
|
+ pImg->uiBitsPerComponent);
|
|
|
+ } else {
|
|
|
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceGray\n");
|
|
|
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile,
|
|
|
+ "\t/Filter [ /ASCII85Decode /FlateDecode ]\n");
|
|
|
+ vFPprintf(pOutFile, "\t/DecodeParms [ null <<\n");
|
|
|
+ vFPprintf(pOutFile, "\t\t/Predictor 10\n");
|
|
|
+ vFPprintf(pOutFile, "\t\t/Colors %d\n", pImg->iComponents);
|
|
|
+ vFPprintf(pOutFile, "\t\t/BitsPerComponent %u\n",
|
|
|
+ pImg->uiBitsPerComponent);
|
|
|
+ vFPprintf(pOutFile, "\t\t/Columns %d\n", pImg->iWidth);
|
|
|
+ vFPprintf(pOutFile, "\t\t>> ]\n");
|
|
|
+ break;
|
|
|
+ case imagetype_is_dib:
|
|
|
+ if (pImg->uiBitsPerComponent <= 8) {
|
|
|
+ vPrintPalette(pOutFile, pImg);
|
|
|
+ } else {
|
|
|
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
|
|
|
+ vFPprintf(pOutFile, "\t/Filter /ASCII85Decode\n");
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ vFPprintf(pOutFile, "\t/ColorSpace /Device%s\n",
|
|
|
+ pImg->bColorImage ? "RGB" : "Gray");
|
|
|
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
|
|
|
+ vFPprintf(pOutFile, "\t/Filter /ASCIIHexDecode\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "ID\n");
|
|
|
+} /* end of vImageProloguePDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vImageEpiloguePDF - clean up after the image
|
|
|
+ */
|
|
|
+void
|
|
|
+vImageEpiloguePDF(diagram_type *pDiag)
|
|
|
+{
|
|
|
+ FILE *pOutFile;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+
|
|
|
+ pOutFile = pDiag->pOutFile;
|
|
|
+
|
|
|
+ /* Correction for the image bytes */
|
|
|
+ lFilePosition = ftell(pOutFile);
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "EI\n");
|
|
|
+ vFPprintf(pOutFile, "Q\n");
|
|
|
+ vFPprintf(pOutFile, "BT\n");
|
|
|
+
|
|
|
+ pDiag->lXleft = 0;
|
|
|
+} /* end of vImageEpiloguePDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * bAddDummyImagePDF - add a dummy image
|
|
|
+ *
|
|
|
+ * return TRUE when successful, otherwise FALSE
|
|
|
+ */
|
|
|
+BOOL
|
|
|
+bAddDummyImagePDF(diagram_type *pDiag, const imagedata_type *pImg)
|
|
|
+{
|
|
|
+ FILE *pOutFile;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+ fail(pImg == NULL);
|
|
|
+
|
|
|
+ if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ iImageCount++;
|
|
|
+
|
|
|
+ DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
|
|
|
+
|
|
|
+ pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
|
|
|
+ vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
|
|
|
+
|
|
|
+ pOutFile = pDiag->pOutFile;
|
|
|
+
|
|
|
+ vFPprintf(pOutFile, "ET\n");
|
|
|
+ vFPprintf(pOutFile, "q %% Image %03d\n", iImageCount);
|
|
|
+ vFPprintf(pOutFile, "\t1.0 w\n");
|
|
|
+ vFPprintf(pOutFile, "\t0.3 G\n");
|
|
|
+ vFPprintf(pOutFile, "\t%.2f %.2f %d %d re\n",
|
|
|
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
|
|
|
+ dDrawUnits2Points(pDiag->lYtop),
|
|
|
+ pImg->iHorSizeScaled,
|
|
|
+ pImg->iVerSizeScaled);
|
|
|
+ vFPprintf(pOutFile, "\tS\n");
|
|
|
+ vFPprintf(pOutFile, "Q\n");
|
|
|
+ vFPprintf(pOutFile, "BT\n");
|
|
|
+
|
|
|
+ pDiag->lXleft = 0;
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+} /* end of bAddDummyImagePDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vAddFontsPDF - add the font information
|
|
|
+ */
|
|
|
+void
|
|
|
+vAddFontsPDF(diagram_type *pDiag)
|
|
|
+{
|
|
|
+ FILE *pOutFile;
|
|
|
+ size_t tIndex;
|
|
|
+
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+
|
|
|
+ pOutFile = pDiag->pOutFile;
|
|
|
+
|
|
|
+ /* The font encoding */
|
|
|
+ vSetLocation(4);
|
|
|
+ vFPprintf(pOutFile, "4 0 obj\n");
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ vFPprintf(pOutFile, "/Type /Encoding\n");
|
|
|
+ vFPprintf(pOutFile, "/BaseEncoding /StandardEncoding\n");
|
|
|
+ vFPprintf(pOutFile, "/Differences [\n");
|
|
|
+ switch (eEncoding) {
|
|
|
+ case encoding_latin_1:
|
|
|
+ for (tIndex = 0;
|
|
|
+ tIndex < elementsof(iso_8859_1);
|
|
|
+ tIndex++) {
|
|
|
+ vFPprintf(pOutFile, "%s\n", iso_8859_1[tIndex]);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case encoding_latin_2:
|
|
|
+ for (tIndex = 0;
|
|
|
+ tIndex < elementsof(iso_8859_2);
|
|
|
+ tIndex++) {
|
|
|
+ vFPprintf(pOutFile, "%s\n", iso_8859_2[tIndex]);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case encoding_cyrillic:
|
|
|
+ werr(1,
|
|
|
+ "The combination PDF and Cyrillic is not supported");
|
|
|
+ break;
|
|
|
+ case encoding_utf_8:
|
|
|
+ werr(1,
|
|
|
+ "The combination PDF and UTF-8 is not supported");
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ DBG_DEC(eEncoding);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "]\n");
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+
|
|
|
+ /* Twelve of the standard type 1 fonts */
|
|
|
+ for (tIndex = 0; tIndex < 12; tIndex++) {
|
|
|
+ vSetLocation(5 + tIndex);
|
|
|
+ vFPprintf(pOutFile, "%u 0 obj\n", 5 + tIndex);
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ vFPprintf(pOutFile, "/Type /Font\n");
|
|
|
+ vFPprintf(pOutFile, "/Subtype /Type1\n");
|
|
|
+ vFPprintf(pOutFile, "/Name /F%u\n", 1 + tIndex);
|
|
|
+ vFPprintf(pOutFile, "/BaseFont /%s\n",
|
|
|
+ atFontname[tIndex].szPDFname);
|
|
|
+ vFPprintf(pOutFile, "/Encoding 4 0 R\n");
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* The Resources */
|
|
|
+ vSetLocation(17);
|
|
|
+ vFPprintf(pOutFile, "17 0 obj\n");
|
|
|
+ vFPprintf(pOutFile, "<<\n");
|
|
|
+ vFPprintf(pOutFile, "/ProcSet [ /PDF /Text ]\n");
|
|
|
+ vFPprintf(pOutFile, "/Font <<\n");
|
|
|
+ for (tIndex = 0; tIndex < 12; tIndex++) {
|
|
|
+ vFPprintf(pOutFile, "\t/F%u %u 0 R\n", 1 + tIndex, 5 + tIndex);
|
|
|
+ }
|
|
|
+ vFPprintf(pOutFile, "\t>>\n");
|
|
|
+ vFPprintf(pOutFile, ">>\n");
|
|
|
+ vFPprintf(pOutFile, "endobj\n");
|
|
|
+ vAddHeader(pDiag);
|
|
|
+} /* end of vAddFontsPDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vPrintPDF - print a PDF string
|
|
|
+ */
|
|
|
+static void
|
|
|
+vPrintPDF(FILE *pFile, const char *szString, size_t tStringLength,
|
|
|
+ USHORT usFontstyle)
|
|
|
+{
|
|
|
+ const UCHAR *aucBytes;
|
|
|
+ double dMove;
|
|
|
+ size_t tCount;
|
|
|
+
|
|
|
+ fail(szString == NULL);
|
|
|
+
|
|
|
+ if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ DBG_DEC_C(usFontSizeCurr < MIN_FONT_SIZE, usFontSizeCurr);
|
|
|
+
|
|
|
+ dMove = 0.0;
|
|
|
+
|
|
|
+ /* Up for superscript */
|
|
|
+ if (bIsSuperscript(usFontstyle) && usFontSizeCurr != 0) {
|
|
|
+ dMove = (double)((usFontSizeCurr + 1) / 2) * 0.375;
|
|
|
+ vFPprintf(pFile, "%.2f Ts\n", dMove);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Down for subscript */
|
|
|
+ if (bIsSubscript(usFontstyle) && usFontSizeCurr != 0) {
|
|
|
+ dMove = (double)usFontSizeCurr * 0.125;
|
|
|
+ vFPprintf(pFile, "%.2f Ts\n", -dMove);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Generate and print the PDF output */
|
|
|
+ aucBytes = (UCHAR *)szString;
|
|
|
+ vFPprintf(pFile, "(");
|
|
|
+ for (tCount = 0; tCount < tStringLength ; tCount++) {
|
|
|
+ switch (aucBytes[tCount]) {
|
|
|
+ case '(':
|
|
|
+ case ')':
|
|
|
+ case '\\':
|
|
|
+ vFPprintf(pFile, "\\%c", szString[tCount]);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if (aucBytes[tCount] < 0x20 ||
|
|
|
+ aucBytes[tCount] == 0x7f ||
|
|
|
+ (aucBytes[tCount] >= 0x81 &&
|
|
|
+ aucBytes[tCount] < 0x8c)) {
|
|
|
+ DBG_HEX(aucBytes[tCount]);
|
|
|
+ vFPprintf(pFile, " ");
|
|
|
+ } else if (aucBytes[tCount] >= 0x80) {
|
|
|
+ vFPprintf(pFile, "\\%03o",
|
|
|
+ (UINT)aucBytes[tCount]);
|
|
|
+ } else {
|
|
|
+ vFPprintf(pFile, "%c", szString[tCount]);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ vFPprintf(pFile, ") Tj\n");
|
|
|
+
|
|
|
+ /* Undo the superscript/subscript move */
|
|
|
+ if (dMove != 0.0) {
|
|
|
+ vFPprintf(pFile, "0 Ts\n");
|
|
|
+ }
|
|
|
+} /* end of vPrintPDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vSetColor - move to the specified color
|
|
|
+ */
|
|
|
+static void
|
|
|
+vSetColor(FILE *pFile, UCHAR ucFontColor)
|
|
|
+{
|
|
|
+ ULONG ulTmp, ulRed, ulGreen, ulBlue;
|
|
|
+
|
|
|
+ ulTmp = ulColor2Color(ucFontColor);
|
|
|
+ ulRed = (ulTmp & 0x0000ff00) >> 8;
|
|
|
+ ulGreen = (ulTmp & 0x00ff0000) >> 16;
|
|
|
+ ulBlue = (ulTmp & 0xff000000) >> 24;
|
|
|
+ vFPprintf(pFile, "%.3f %.3f %.3f rg\n",
|
|
|
+ ulRed / 255.0, ulGreen / 255.0, ulBlue / 255.0);
|
|
|
+} /* end of vSetColor */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vMove2NextLinePDF - move to the next line
|
|
|
+ */
|
|
|
+void
|
|
|
+vMove2NextLinePDF(diagram_type *pDiag, USHORT usFontSize)
|
|
|
+{
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
|
|
|
+
|
|
|
+ pDiag->lYtop -= lComputeLeading(usFontSize);
|
|
|
+} /* end of vMove2NextLinePDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * vSubstringPDF - print a sub string
|
|
|
+ */
|
|
|
+void
|
|
|
+vSubstringPDF(diagram_type *pDiag,
|
|
|
+ char *szString, size_t tStringLength, long lStringWidth,
|
|
|
+ UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
|
|
|
+ USHORT usFontSize, USHORT usMaxFontSize)
|
|
|
+{
|
|
|
+ size_t tFontIndex;
|
|
|
+
|
|
|
+ fail(pDiag == NULL || szString == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+ fail(pDiag->lXleft < 0);
|
|
|
+ fail(tStringLength != strlen(szString));
|
|
|
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
|
|
|
+ fail(usMaxFontSize < MIN_FONT_SIZE || usMaxFontSize > MAX_FONT_SIZE);
|
|
|
+ fail(usFontSize > usMaxFontSize);
|
|
|
+
|
|
|
+ if (szString[0] == '\0' || tStringLength == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ vMoveTo(pDiag, lComputeLeading(usMaxFontSize));
|
|
|
+ if (tFontRef != tFontRefCurr || usFontSize != usFontSizeCurr) {
|
|
|
+ tFontIndex = tGetFontIndex(tFontRef);
|
|
|
+ vFPprintf(pDiag->pOutFile, "/F%u %.1f Tf\n",
|
|
|
+ 1 + tFontIndex, (double)usFontSize / 2.0);
|
|
|
+ tFontRefCurr = tFontRef;
|
|
|
+ usFontSizeCurr = usFontSize;
|
|
|
+ }
|
|
|
+ if ((int)ucFontColor != iFontColorCurr) {
|
|
|
+ vSetColor(pDiag->pOutFile, ucFontColor);
|
|
|
+ iFontColorCurr = (int)ucFontColor;
|
|
|
+ }
|
|
|
+ vPrintPDF(pDiag->pOutFile, szString, tStringLength, usFontstyle);
|
|
|
+ pDiag->lXleft += lStringWidth;
|
|
|
+} /* end of vSubstringPDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create an start of paragraph by moving the y-top mark
|
|
|
+ */
|
|
|
+void
|
|
|
+vStartOfParagraphPDF(diagram_type *pDiag, long lBeforeIndentation)
|
|
|
+{
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(lBeforeIndentation < 0);
|
|
|
+
|
|
|
+ pDiag->lXleft = 0;
|
|
|
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
|
|
|
+} /* end of vStartOfParagraphPDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create an end of paragraph by moving the y-top mark
|
|
|
+ */
|
|
|
+void
|
|
|
+vEndOfParagraphPDF(diagram_type *pDiag,
|
|
|
+ USHORT usFontSize, long lAfterIndentation)
|
|
|
+{
|
|
|
+ fail(pDiag == NULL);
|
|
|
+ fail(pDiag->pOutFile == NULL);
|
|
|
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
|
|
|
+ fail(lAfterIndentation < 0);
|
|
|
+
|
|
|
+ if (pDiag->lXleft > 0) {
|
|
|
+ /* To the start of the line */
|
|
|
+ vMove2NextLinePDF(pDiag, usFontSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ pDiag->lXleft = 0;
|
|
|
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
|
|
|
+} /* end of vEndOfParagraphPDF */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create an end of page
|
|
|
+ */
|
|
|
+void
|
|
|
+vEndOfPagePDF(diagram_type *pDiag, BOOL bNewSection)
|
|
|
+{
|
|
|
+ vMove2NextPage(pDiag, bNewSection);
|
|
|
+} /* end of vEndOfPagePDF */
|