home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / anwor032.zip / antiword.0.32 / postscript.c < prev    next >
C/C++ Source or Header  |  2001-09-24  |  26KB  |  946 lines

  1. /*
  2.  * postscript.c
  3.  * Copyright (C) 1999-2001 A.J. van Os; Released under GPL
  4.  *
  5.  * Description:
  6.  * Functions to deal with the PostScript format
  7.  *
  8.  *================================================================
  9.  * The function vImagePrologue is based on:
  10.  * jpeg2ps - convert JPEG compressed images to PostScript Level 2
  11.  * Copyright (C) 1994-99 Thomas Merz (tm@muc.de)
  12.  *================================================================
  13.  * The credit should go to him, but all the bugs are mine.
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <time.h>
  21. #include "version.h"
  22. #include "antiword.h"
  23.  
  24. /* The output must be in PostScript */
  25. static BOOL        bUsePostScript = FALSE;
  26. /* The character set */
  27. static encoding_type    eEncoding = encoding_neutral;
  28. /* The image level */
  29. static image_level_enum    eImageLevel = level_default;
  30. /* The output must use landscape orientation */
  31. static BOOL        bUseLandscape = FALSE;
  32. /* The height of a PostScript page (in DrawUnits) */
  33. static long        lPageHeight = LONG_MAX;
  34. /* Current time for a PS header */
  35. static const char    *szCreationDate = NULL;
  36. /* Current creator for a PS header */
  37. static const char    *szCreator = NULL;
  38. /* Current font information */
  39. static draw_fontref    tFontRefCurr = (draw_fontref)-1;
  40. static int        iFontsizeCurr = -1;
  41. static int        iColorCurr = -1;
  42. /* Current vertical position information */
  43. static long        lYtopCurr = -1;
  44. /* PostScript page counter */
  45. static int    iPageCount = 0;
  46. /* Image counter */
  47. static int    iImageCount = 0;
  48.  
  49. static char iso_8859_1_data[] = { "\
  50. /newcodes    % ISO-8859-1 character encodings\n\
  51. [\n\
  52. 160/space 161/exclamdown 162/cent 163/sterling 164/currency\n\
  53. 165/yen 166/brokenbar 167/section 168/dieresis 169/copyright\n\
  54. 170/ordfeminine 171/guillemotleft 172/logicalnot 173/hyphen 174/registered\n\
  55. 175/macron 176/degree 177/plusminus 178/twosuperior 179/threesuperior\n\
  56. 180/acute 181/mu 182/paragraph 183/periodcentered 184/cedilla\n\
  57. 185/onesuperior 186/ordmasculine 187/guillemotright 188/onequarter\n\
  58. 189/onehalf 190/threequarters 191/questiondown 192/Agrave 193/Aacute\n\
  59. 194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198/AE 199/Ccedilla\n\
  60. 200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204/Igrave 205/Iacute\n\
  61. 206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve 211/Oacute\n\
  62. 212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash\n\
  63. 217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn\n\
  64. 223/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde\n\
  65. 228/adieresis 229/aring 230/ae 231/ccedilla 232/egrave 233/eacute\n\
  66. 234/ecircumflex 235/edieresis 236/igrave 237/iacute 238/icircumflex\n\
  67. 239/idieresis 240/eth 241/ntilde 242/ograve 243/oacute 244/ocircumflex\n\
  68. 245/otilde 246/odieresis 247/divide 248/oslash 249/ugrave 250/uacute\n\
  69. 251/ucircumflex 252/udieresis 253/yacute 254/thorn 255/ydieresis\n\
  70. ] bind def\n\
  71. \n\
  72. /reencdict 12 dict def\n\
  73. \n\
  74. " };
  75.  
  76. static char iso_8859_2_data[] = { "\
  77. /newcodes    % ISO-8859-2 character encodings\n\
  78. [\n\
  79. 160/space 161/Aogonek 162/breve 163/Lslash 164/currency 165/Lcaron\n\
  80. 166/Sacute 167/section 168/dieresis 169/Scaron 170/Scommaaccent\n\
  81. 171/Tcaron 172/Zacute 173/hyphen 174/Zcaron 175/Zdotaccent 176/degree\n\
  82. 177/aogonek 178/ogonek 179/lslash 180/acute 181/lcaron 182/sacute\n\
  83. 183/caron 184/cedilla 185/scaron 186/scommaaccent 187/tcaron\n\
  84. 188/zacute 189/hungarumlaut 190/zcaron 191/zdotaccent 192/Racute\n\
  85. 193/Aacute 194/Acircumflex 195/Abreve 196/Adieresis 197/Lacute\n\
  86. 198/Cacute 199/Ccedilla 200/Ccaron 201/Eacute 202/Eogonek\n\
  87. 203/Edieresis 204/Ecaron 205/Iacute 206/Icircumflex 207/Dcaron\n\
  88. 208/Dcroat 209/Nacute 210/Ncaron 211/Oacute 212/Ocircumflex\n\
  89. 213/Ohungarumlaut 214/Odieresis 215/multiply 216/Rcaron 217/Uring\n\
  90. 218/Uacute 219/Uhungarumlaut 220/Udieresis 221/Yacute 222/Tcommaaccent\n\
  91. 223/germandbls 224/racute 225/aacute 226/acircumflex 227/abreve\n\
  92. 228/adieresis 229/lacute 230/cacute 231/ccedilla 232/ccaron 233/eacute\n\
  93. 234/eogonek 235/edieresis 236/ecaron 237/iacute 238/icircumflex\n\
  94. 239/dcaron 240/dcroat 241/nacute 242/ncaron 243/oacute 244/ocircumflex\n\
  95. 245/ohungarumlaut 246/odieresis 247/divide 248/rcaron 249/uring\n\
  96. 250/uacute 251/uhungarumlaut 252/udieresis 253/yacute 254/tcommaaccent\n\
  97. 255/dotaccent\n\
  98. ] bind def\n\
  99. \n\
  100. /reencdict 12 dict def\n\
  101. \n\
  102. " };
  103.  
  104. static char iso_8859_x_func[] = { "\
  105. % change fonts using ISO-8859-x characters\n\
  106. /ChgFnt        % size psname natname => font\n\
  107. {\n\
  108.     dup FontDirectory exch known        % is re-encoded name known?\n\
  109.     { exch pop }                % yes, get rid of long name\n\
  110.     { dup 3 1 roll ReEncode } ifelse    % no, re-encode it\n\
  111.     findfont exch scalefont setfont\n\
  112. } bind def\n\
  113. \n\
  114. /ReEncode\n\
  115. {\n\
  116. reencdict begin\n\
  117.     /newname exch def\n\
  118.     /basename exch def\n\
  119.     /basedict basename findfont def\n\
  120.     /newfont basedict maxlength dict def\n\
  121.     basedict\n\
  122.     { exch dup /FID ne\n\
  123.         { dup /Encoding eq\n\
  124.             { exch dup length array copy newfont 3 1 roll put }\n\
  125.             { exch newfont 3 1 roll put } ifelse\n\
  126.         }\n\
  127.         { pop pop } ifelse\n\
  128.     } forall\n\
  129.     newfont /FontName newname put\n\
  130.     newcodes aload pop newcodes length 2 idiv\n\
  131.     { newfont /Encoding get 3 1 roll put } repeat\n\
  132.     newname newfont definefont pop\n\
  133. end\n\
  134. } bind def\n\
  135. \n\
  136. " };
  137.  
  138. static char misc_func[] = { "\
  139. % draw a line and show the string\n\
  140. /LineShow    % string linewidth movement\n\
  141. {\n\
  142.     gsave\n\
  143.         0 exch rmoveto\n\
  144.         setlinewidth\n\
  145.         dup\n\
  146.         stringwidth pop\n\
  147.         0 rlineto stroke\n\
  148.     grestore\n\
  149.     show\n\
  150. } bind def\n\
  151. \n\
  152. % begin an EPS file (level 2 and up)\n\
  153. /BeginEPSF\n\
  154. {\n\
  155.     /b4_Inc_state save def\n\
  156.     /dict_count countdictstack def\n\
  157.     /op_count count 1 sub def\n\
  158.     userdict begin\n\
  159.         /showpage { } def\n\
  160.         0 setgray 0 setlinecap\n\
  161.         1 setlinewidth 0 setlinejoin\n\
  162.         10 setmiterlimit [ ] 0 setdash newpath\n\
  163.         false setstrokeadjust false setoverprint\n\
  164. } bind def\n\
  165. \n\
  166. % end an EPS file\n\
  167. /EndEPSF {\n\
  168.     count op_count sub { pop } repeat\n\
  169.     countdictstack dict_count sub { end } repeat\n\
  170.     b4_Inc_state restore\n\
  171. } bind def\n\
  172. \n\
  173. " };
  174.  
  175.  
  176. /*
  177.  * vAddPageSetup - add the page setup
  178.  */
  179. static void
  180. vAddPageSetup(FILE *pOutFile)
  181. {
  182.     if (bUseLandscape) {
  183.         fprintf(pOutFile, "%%%%BeginPageSetup\n");
  184.         fprintf(pOutFile, "90 rotate\n");
  185.         fprintf(pOutFile, "0.00 %.2f translate\n",
  186.                     -dDrawUnits2Points(lPageHeight));
  187.         fprintf(pOutFile, "%%%%EndPageSetup\n");
  188.     }
  189. } /* end of vAddPageSetup */
  190.  
  191. /*
  192.  * vMove2NextPage - move to the start of the next page
  193.  */
  194. static void
  195. vMove2NextPage(diagram_type *pDiag)
  196. {
  197.     fail(pDiag == NULL);
  198.     fail(!bUsePostScript);
  199.  
  200.     fprintf(pDiag->pOutFile, "showpage\n");
  201.     iPageCount++;
  202.     fprintf(pDiag->pOutFile, "%%%%Page: %d %d\n", iPageCount, iPageCount);
  203.     vAddPageSetup(pDiag->pOutFile);
  204.     pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
  205.     lYtopCurr = -1;
  206. } /* end of vMove2NextPage */
  207.  
  208. /*
  209.  * vMoveToPS - move to the given X,Y coordinates (Postscript)
  210.  *
  211.  * Move the current position of the given diagram to its X,Y coordinates,
  212.  * start on a new page if needed
  213.  */
  214. static void
  215. vMoveToPS(diagram_type *pDiag, long lLastVerticalMovement)
  216. {
  217.     fail(pDiag == NULL);
  218.     fail(pDiag->pOutFile == NULL);
  219.  
  220.     if (pDiag->lYtop < PS_BOTTOM_MARGIN) {
  221.         vMove2NextPage(pDiag);
  222.         /* Repeat the last vertical movement on the new page */
  223.         pDiag->lYtop -= lLastVerticalMovement;
  224.     }
  225.     fail(pDiag->lYtop < PS_BOTTOM_MARGIN);
  226.  
  227.     if (pDiag->lYtop != lYtopCurr) {
  228.         fprintf(pDiag->pOutFile, "%.2f %.2f moveto\n",
  229.             dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
  230.             dDrawUnits2Points(pDiag->lYtop));
  231.         lYtopCurr = pDiag->lYtop;
  232.     }
  233. } /* end of vMoveToPS */
  234.  
  235. /*
  236.  * vPrologue - perform the PostScript initialization
  237.  */
  238. static void
  239. vPrologue(FILE *pOutFile, const char *szTask, const char *szFilename)
  240. {
  241.     options_type    tOptions;
  242.     const char    *szTmp;
  243.     time_t    tTime;
  244.  
  245.     fail(pOutFile == NULL);
  246.     fail(szTask == NULL || szTask[0] == '\0');
  247.  
  248.     vGetOptions(&tOptions);
  249.     lPageHeight = lPoints2DrawUnits(tOptions.iPageHeight);
  250.     DBG_DEC(lPageHeight);
  251.     bUsePostScript = tOptions.bUseOutlineFonts;
  252.     bUseLandscape = tOptions.bUseLandscape;
  253.     eEncoding = tOptions.eEncoding;
  254.     eImageLevel = tOptions.eImageLevel;
  255.     tFontRefCurr = (draw_fontref)-1;
  256.     iFontsizeCurr = -1;
  257.     iColorCurr = -1;
  258.     lYtopCurr = -1;
  259.     iImageCount = 0;
  260.  
  261.     if (!bUsePostScript) {
  262.         return;
  263.     }
  264.  
  265.     szCreator = szTask;
  266.  
  267.     fprintf(pOutFile, "%%!PS-Adobe-2.0\n");
  268.     fprintf(pOutFile, "%%%%Title: %s\n", szBasename(szFilename));
  269.     fprintf(pOutFile, "%%%%Creator: %s %s\n", szCreator, VERSIONSTRING);
  270.     szTmp = getenv("LOGNAME");
  271.     if (szTmp == NULL || szTmp[0] == '\0') {
  272.         szTmp = getenv("USER");
  273.         if (szTmp == NULL || szTmp[0] == '\0') {
  274.             szTmp = "unknown";
  275.         }
  276.     }
  277.     fprintf(pOutFile, "%%%%For: %s\n", szTmp);
  278.     errno = 0;
  279.     tTime = time(NULL);
  280.     if (tTime == (time_t)-1 && errno != 0) {
  281.         szCreationDate = NULL;
  282.     } else {
  283.         szCreationDate = ctime(&tTime);
  284.     }
  285.     if (szCreationDate == NULL || szCreationDate[0] == '\0') {
  286.         szCreationDate = "unknown\n";
  287.     }
  288.     fprintf(pOutFile, "%%%%CreationDate: %s", szCreationDate);
  289.     if (bUseLandscape) {
  290.         fprintf(pOutFile, "%%%%Orientation: Landscape\n");
  291.         fprintf(pOutFile, "%%%%BoundingBox: 0 0 %d %d\n",
  292.                 tOptions.iPageHeight, tOptions.iPageWidth);
  293.     } else {
  294.         fprintf(pOutFile, "%%%%Orientation: Portrait\n");
  295.         fprintf(pOutFile, "%%%%BoundingBox: 0 0 %d %d\n",
  296.                 tOptions.iPageWidth, tOptions.iPageHeight);
  297.     }
  298. } /* end of vPrologue */
  299.  
  300. /*
  301.  * vEpilogue - clean up after everything is done
  302.  */
  303. static void
  304. vEpilogue(FILE *pFile)
  305. {
  306.     if (!bUsePostScript) {
  307.         fprintf(pFile, "\n");
  308.         return;
  309.     }
  310.  
  311.     fprintf(pFile, "%%%%Trailer\n");
  312.     fprintf(pFile, "%%%%Pages: %d\n", iPageCount);
  313.     fprintf(pFile, "%%%%EOF\n");
  314.     szCreationDate = NULL;
  315.     szCreator = NULL;
  316. } /* end of vEpilogue */
  317.  
  318. /*
  319.  * vPrintPalette - print a postscript palette
  320.  */
  321. static void
  322. vPrintPalette(FILE *pOutFile, const imagedata_type *pImg)
  323. {
  324.     int    iIndex;
  325.  
  326.     fail(pOutFile == NULL);
  327.     fail(pImg == NULL);
  328.     fail(pImg->iColorsUsed < 2);
  329.     fail(pImg->iColorsUsed > 256);
  330.  
  331.     fprintf(pOutFile, "[ /Indexed\n");
  332.     fprintf(pOutFile, "\t/Device%s %d\n",
  333.         pImg->bColorImage ? "RGB" : "Gray", pImg->iColorsUsed - 1);
  334.     fprintf(pOutFile, "<");
  335.     for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
  336.         fprintf(pOutFile, "%02x", pImg->aucPalette[iIndex][0]);
  337.         if (pImg->bColorImage) {
  338.             fprintf(pOutFile, "%02x%02x",
  339.                 pImg->aucPalette[iIndex][1],
  340.                 pImg->aucPalette[iIndex][2]);
  341.         }
  342.         if (iIndex % 8 == 7) {
  343.             fprintf(pOutFile, "\n");
  344.         } else {
  345.             fprintf(pOutFile, " ");
  346.         }
  347.     }
  348.     fprintf(pOutFile, ">\n");
  349.     fprintf(pOutFile, "] setcolorspace\n");
  350. } /* end of vPrintPalette */
  351.  
  352. /*
  353.  * vImagePrologue - perform the Encapsulated PostScript initialization
  354.  */
  355. void
  356. vImagePrologue(diagram_type *pDiag, const imagedata_type *pImg)
  357. {
  358.     FILE    *pOutFile;
  359.  
  360.     fail(pDiag == NULL);
  361.     fail(pDiag->pOutFile == NULL);
  362.     fail(pImg == NULL);
  363.  
  364.     if (!bUsePostScript) {
  365.         return;
  366.     }
  367.  
  368.     if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
  369.         return;
  370.     }
  371.  
  372.     fail(szCreationDate == NULL);
  373.     fail(szCreator == NULL);
  374.     fail(eImageLevel == level_no_images);
  375.  
  376.     iImageCount++;
  377.  
  378.     DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
  379.  
  380.     pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
  381.     vMoveToPS(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
  382.  
  383.     pOutFile = pDiag->pOutFile;
  384.  
  385.     fprintf(pOutFile, "BeginEPSF\n");
  386.     fprintf(pOutFile, "%%%%BeginDocument: image%03d.eps\n", iImageCount);
  387.     fprintf(pOutFile, "%%!PS-Adobe-2.0 EPSF-2.0\n");
  388.     fprintf(pOutFile, "%%%%Creator: %s %s\n", szCreator, VERSIONSTRING);
  389.     fprintf(pOutFile, "%%%%Title: Image %03d\n", iImageCount);
  390.     fprintf(pOutFile, "%%%%CreationDate: %s", szCreationDate);
  391.     fprintf(pOutFile, "%%%%BoundingBox: 0 0 %d %d\n",
  392.                 pImg->iHorSizeScaled, pImg->iVerSizeScaled);
  393.     fprintf(pOutFile, "%%%%DocumentData: Clean7Bit\n");
  394.     fprintf(pOutFile, "%%%%LanguageLevel: 2\n");
  395.     fprintf(pOutFile, "%%%%EndComments\n");
  396.     fprintf(pOutFile, "%%%%BeginProlog\n");
  397.     fprintf(pOutFile, "%%%%EndProlog\n");
  398.     fprintf(pOutFile, "%%%%Page: 1 1\n");
  399.  
  400.     fprintf(pOutFile, "save\n");
  401.  
  402.     switch (pImg->eImageType) {
  403.     case imagetype_is_jpeg:
  404.         fprintf(pOutFile, "/Data1 currentfile ");
  405.         fprintf(pOutFile, "/ASCII85Decode filter def\n");
  406.         fprintf(pOutFile, "/Data Data1 << ");
  407.         fprintf(pOutFile, ">> /DCTDecode filter def\n");
  408.         switch (pImg->iComponents) {
  409.         case 1:
  410.             fprintf(pOutFile, "/DeviceGray setcolorspace\n");
  411.             break;
  412.         case 3:
  413.             fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
  414.             break;
  415.         case 4:
  416.             fprintf(pOutFile, "/DeviceCMYK setcolorspace\n");
  417.             break;
  418.         default:
  419.             DBG_DEC(pImg->iComponents);
  420.             break;
  421.         }
  422.         break;
  423.     case imagetype_is_png:
  424.         if (eImageLevel == level_gs_special) {
  425.             fprintf(pOutFile,
  426.             "/Data2 currentfile /ASCII85Decode filter def\n");
  427.             fprintf(pOutFile,
  428.             "/Data1 Data2 << >> /FlateDecode filter def\n");
  429.             fprintf(pOutFile, "/Data Data1 <<\n");
  430.             fprintf(pOutFile, "\t/Colors %d\n", pImg->iComponents);
  431.             fprintf(pOutFile, "\t/BitsPerComponent %d\n",
  432.                         pImg->iBitsPerComponent);
  433.             fprintf(pOutFile, "\t/Columns %d\n", pImg->iWidth);
  434.             fprintf(pOutFile,
  435.                 ">> /PNGPredictorDecode filter def\n");
  436.         } else {
  437.             fprintf(pOutFile,
  438.             "/Data1 currentfile /ASCII85Decode filter def\n");
  439.             fprintf(pOutFile,
  440.             "/Data Data1 << >> /FlateDecode filter def\n");
  441.         }
  442.         if (pImg->iComponents == 3) {
  443.             fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
  444.         } else if (pImg->iColorsUsed > 0) {
  445.             vPrintPalette(pOutFile, pImg);
  446.         } else {
  447.             fprintf(pOutFile, "/DeviceGray setcolorspace\n");
  448.         }
  449.         break;
  450.     case imagetype_is_dib:
  451.         fprintf(pOutFile, "/Data currentfile ");
  452.         fprintf(pOutFile, "/ASCII85Decode filter def\n");
  453.         if (pImg->iBitsPerComponent <= 8) {
  454.             vPrintPalette(pOutFile, pImg);
  455.         } else {
  456.             fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
  457.         }
  458.         break;
  459.     default:
  460.         fprintf(pOutFile, "/Data currentfile ");
  461.         fprintf(pOutFile, "/ASCIIHexDecode filter def\n");
  462.         fprintf(pOutFile, "/Device%s setcolorspace\n",
  463.             pImg->bColorImage ? "RGB" : "Gray");
  464.         break;
  465.     }
  466.  
  467.     /* Translate to lower left corner of image */
  468.     fprintf(pOutFile, "%.2f %.2f translate\n",
  469.             dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
  470.             dDrawUnits2Points(pDiag->lYtop));
  471.  
  472.     fprintf(pOutFile, "%d %d scale\n",
  473.                 pImg->iHorSizeScaled, pImg->iVerSizeScaled);
  474.  
  475.     fprintf(pOutFile, "{ <<\n");
  476.     fprintf(pOutFile, "\t/ImageType 1\n");
  477.     fprintf(pOutFile, "\t/Width %d\n", pImg->iWidth);
  478.     fprintf(pOutFile, "\t/Height %d\n", pImg->iHeight);
  479.     if (pImg->eImageType == imagetype_is_dib) {
  480.         /* Scanning from left to right and bottom to top */
  481.         fprintf(pOutFile, "\t/ImageMatrix [ %d 0 0 %d 0 0 ]\n",
  482.             pImg->iWidth, pImg->iHeight);
  483.     } else {
  484.         /* Scanning from left to right and top to bottom */
  485.         fprintf(pOutFile, "\t/ImageMatrix [ %d 0 0 %d 0 %d ]\n",
  486.             pImg->iWidth, -pImg->iHeight, pImg->iHeight);
  487.     }
  488.     fprintf(pOutFile, "\t/DataSource Data\n");
  489.  
  490.     switch (pImg->eImageType) {
  491.     case imagetype_is_jpeg:
  492.         fprintf(pOutFile, "\t/BitsPerComponent 8\n");
  493.         switch (pImg->iComponents) {
  494.         case 1:
  495.             fprintf(pOutFile, "\t/Decode [0 1]\n");
  496.             break;
  497.         case 3:
  498.             fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
  499.             break;
  500.         case 4:
  501.             if (pImg->bAdobe) {
  502.                 /*
  503.                  * Adobe-conforming CMYK file
  504.                  * applying workaround for color inversion
  505.                  */
  506.                 fprintf(pOutFile,
  507.                     "\t/Decode [1 0 1 0 1 0 1 0]\n");
  508.             } else {
  509.                 fprintf(pOutFile,
  510.                     "\t/Decode [0 1 0 1 0 1 0 1]\n");
  511.             }
  512.             break;
  513.         default:
  514.             DBG_DEC(pImg->iComponents);
  515.             break;
  516.         }
  517.         break;
  518.     case imagetype_is_png:
  519.         if (pImg->iComponents == 3) {
  520.             fprintf(pOutFile, "\t/BitsPerComponent 8\n");
  521.             fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
  522.         } else if (pImg->iColorsUsed > 0) {
  523.             fail(pImg->iBitsPerComponent > 8);
  524.             fprintf(pOutFile, "\t/BitsPerComponent %d\n",
  525.                     pImg->iBitsPerComponent);
  526.             fprintf(pOutFile, "\t/Decode [0 %d]\n",
  527.                     (1 << pImg->iBitsPerComponent) - 1);
  528.         } else {
  529.             fprintf(pOutFile, "\t/BitsPerComponent 8\n");
  530.             fprintf(pOutFile, "\t/Decode [0 1]\n");
  531.         }
  532.         break;
  533.     case imagetype_is_dib:
  534.         fprintf(pOutFile, "\t/BitsPerComponent 8\n");
  535.         if (pImg->iBitsPerComponent <= 8) {
  536.             fprintf(pOutFile, "\t/Decode [0 255]\n");
  537.         } else {
  538.             fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
  539.         }
  540.         break;
  541.     default:
  542.         fprintf(pOutFile, "\t/BitsPerComponent 8\n");
  543.         if (pImg->bColorImage) {
  544.             fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
  545.         } else {
  546.             fprintf(pOutFile, "\t/Decode [0 1]\n");
  547.         }
  548.         break;
  549.     }
  550.  
  551.     fprintf(pOutFile, "  >> image\n");
  552.     fprintf(pOutFile, "  Data closefile\n");
  553.     fprintf(pOutFile, "  showpage\n");
  554.     fprintf(pOutFile, "  restore\n");
  555.     fprintf(pOutFile, "} exec\n");
  556. } /* end of vImagePrologue */
  557.  
  558. /*
  559.  * vImageEpilogue - clean up after Encapsulated PostScript
  560.  */
  561. void
  562. vImageEpilogue(diagram_type *pDiag)
  563. {
  564.     FILE    *pOutFile;
  565.  
  566.     if (!bUsePostScript) {
  567.         return;
  568.     }
  569.  
  570.     fail(pDiag == NULL);
  571.     fail(pDiag->pOutFile == NULL);
  572.  
  573.     pOutFile = pDiag->pOutFile;
  574.  
  575.     fprintf(pOutFile, "%%%%EOF\n");
  576.     fprintf(pOutFile, "%%%%EndDocument\n");
  577.     fprintf(pOutFile, "EndEPSF\n");
  578.  
  579.     pDiag->lXleft = 0;
  580. } /* end of vImageEpilogue */
  581.  
  582. /*
  583.  * bAddDummyImage - add a dummy image
  584.  *
  585.  * return TRUE when successful, otherwise FALSE
  586.  */
  587. BOOL
  588. bAddDummyImage(diagram_type *pDiag, const imagedata_type *pImg)
  589. {
  590.     FILE    *pOutFile;
  591.  
  592.     fail(pDiag == NULL);
  593.     fail(pDiag->pOutFile == NULL);
  594.     fail(pImg == NULL);
  595.  
  596.     if (!bUsePostScript) {
  597.         return FALSE;
  598.     }
  599.  
  600.     if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
  601.         return FALSE;
  602.     }
  603.  
  604.     iImageCount++;
  605.  
  606.     DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
  607.  
  608.     pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
  609.     vMoveToPS(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
  610.  
  611.     pOutFile = pDiag->pOutFile;
  612.  
  613.     fprintf(pOutFile, "gsave %% Image %03d\n", iImageCount);
  614.     fprintf(pOutFile, "\tnewpath\n");
  615.     fprintf(pOutFile, "\t%.2f %.2f moveto\n",
  616.             dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
  617.             dDrawUnits2Points(pDiag->lYtop));
  618.     fprintf(pOutFile, "\t1.0 setlinewidth\n");
  619.     fprintf(pOutFile, "\t0.3 setgray\n");
  620.     fprintf(pOutFile, "\t0 %d rlineto\n", pImg->iVerSizeScaled);
  621.     fprintf(pOutFile, "\t%d 0 rlineto\n", pImg->iHorSizeScaled);
  622.     fprintf(pOutFile, "\t0 %d rlineto\n", -pImg->iVerSizeScaled);
  623.     fprintf(pOutFile, "\tclosepath\n");
  624.     fprintf(pOutFile, "\tstroke\n");
  625.     fprintf(pOutFile, "grestore\n");
  626.  
  627.     pDiag->lXleft = 0;
  628.  
  629.     return TRUE;
  630. } /* end of bAddDummyImage */
  631.  
  632. /*
  633.  * pCreateDiagram - create and initialize a diagram
  634.  *
  635.  * remark: does not return if the diagram can't be created
  636.  */
  637. diagram_type *
  638. pCreateDiagram(const char *szTask, const char *szFilename)
  639. {
  640.     diagram_type    *pDiag;
  641.  
  642.     fail(szTask == NULL || szTask[0] == '\0');
  643.     DBG_MSG("pCreateDiagram");
  644.  
  645.     /* Get the necessary memory */
  646.     pDiag = xmalloc(sizeof(diagram_type));
  647.     /* Initialization */
  648.     pDiag->pOutFile = stdout;
  649.     vPrologue(pDiag->pOutFile, szTask, szFilename);
  650.     iPageCount = 0;
  651.     pDiag->lXleft = 0;
  652.     if (bUsePostScript) {
  653.         pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
  654.     } else {
  655.         pDiag->lYtop = 0;
  656.     }
  657.     /* Return success */
  658.     return pDiag;
  659. } /* end of pCreateDiagram */
  660.  
  661. /*
  662.  * vDestroyDiagram - remove a diagram by freeing the memory it uses
  663.  */
  664. void
  665. vDestroyDiagram(diagram_type *pDiag)
  666. {
  667.     DBG_MSG("vDestroyDiagram");
  668.  
  669.     fail(pDiag == NULL);
  670.  
  671.     if (pDiag == NULL) {
  672.         return;
  673.     }
  674.     if (bUsePostScript && pDiag->lYtop < lPageHeight - PS_TOP_MARGIN) {
  675.         fprintf(pDiag->pOutFile, "showpage\n");
  676.     }
  677.     vEpilogue(pDiag->pOutFile);
  678.     pDiag = xfree(pDiag);
  679. } /* end of vDestroyDiagram */
  680.  
  681. /*
  682.  * vAddFonts2Diagram - add the list of fonts and complete the prologue
  683.  */
  684. void
  685. vAddFonts2Diagram(diagram_type *pDiag)
  686. {
  687.     FILE    *pOutFile;
  688.     const font_table_type *pTmp, *pTmp2;
  689.     int    iLineLen;
  690.     BOOL    bFound;
  691.  
  692.     fail(pDiag == NULL);
  693.     fail(pDiag->pOutFile == NULL);
  694.  
  695.     if (!bUsePostScript) {
  696.         return;
  697.     }
  698.  
  699.     pOutFile = pDiag->pOutFile;
  700.     iLineLen = fprintf(pOutFile, "%%%%DocumentFonts:");
  701.  
  702.     if (tGetFontTableLength() == 0) {
  703.         iLineLen += fprintf(pOutFile, " Courier");
  704.     } else {
  705.         pTmp = NULL;
  706.         while ((pTmp = pGetNextFontTableRecord(pTmp)) != NULL) {
  707.             /* Print the document fonts */
  708.             bFound = FALSE;
  709.             pTmp2 = NULL;
  710.             while ((pTmp2 = pGetNextFontTableRecord(pTmp2))
  711.                     != NULL && pTmp2 < pTmp) {
  712.                 bFound = STREQ(pTmp2->szOurFontname,
  713.                         pTmp->szOurFontname);
  714.                 if (bFound) {
  715.                     break;
  716.                 }
  717.             }
  718.             if (bFound) {
  719.                 continue;
  720.             }
  721.             if (iLineLen + (int)strlen(pTmp->szOurFontname) > 78) {
  722.                 fprintf(pOutFile, "\n%%%%+");
  723.                 iLineLen = 3;
  724.             }
  725.             iLineLen += fprintf(pOutFile,
  726.                     " %s", pTmp->szOurFontname);
  727.         }
  728.     }
  729.     fprintf(pOutFile, "\n");
  730.     fprintf(pOutFile, "%%%%Pages: (atend)\n");
  731.     fprintf(pOutFile, "%%%%EndComments\n");
  732.     fprintf(pOutFile, "%%%%BeginProlog\n");
  733.  
  734.     switch (eEncoding) {
  735.     case encoding_iso_8859_1:
  736.         fprintf(pOutFile, "%s\n%s", iso_8859_1_data, iso_8859_x_func);
  737.         break;
  738.     case encoding_iso_8859_2:
  739.         fprintf(pOutFile, "%s\n%s", iso_8859_2_data, iso_8859_x_func);
  740.         break;
  741.     default:
  742.         DBG_DEC(eEncoding);
  743.         break;
  744.     }
  745.  
  746.     /* The rest of the functions */
  747.     fprintf(pOutFile, "%s", misc_func);
  748.     fprintf(pOutFile, "%%%%EndProlog\n");
  749.     iPageCount = 1;
  750.     fprintf(pDiag->pOutFile, "%%%%Page: %d %d\n", iPageCount, iPageCount);
  751.     vAddPageSetup(pDiag->pOutFile);
  752. } /* end of vAddFonts2Diagram */
  753.  
  754. /*
  755.  * vPrintPS - print a PostScript string
  756.  */
  757. static void
  758. vPrintPS(FILE *pFile, const char *szString, int iStringLength,
  759.         unsigned char ucFontstyle)
  760. {
  761.     int iCount;
  762.     const unsigned char *ucBytes;
  763.  
  764.     fail(szString == NULL || iStringLength < 0);
  765.  
  766.     if (szString == NULL || szString[0] == '\0' || iStringLength <= 0) {
  767.         return;
  768.     }
  769.  
  770.     ucBytes = (unsigned char *)szString;
  771.     (void)putc('(', pFile);
  772.     for (iCount = 0; iCount < iStringLength ; iCount++) {
  773.         switch (ucBytes[iCount]) {
  774.         case '(':
  775.         case ')':
  776.         case '\\':
  777.             (void)putc('\\', pFile);
  778.             (void)putc(szString[iCount], pFile);
  779.             break;
  780.         default:
  781.             if (ucBytes[iCount] < 0x20 ||
  782.                 (ucBytes[iCount] >= 0x7f &&
  783.                  ucBytes[iCount] < 0xa0)) {
  784.                 DBG_HEX(ucBytes[iCount]);
  785.                 (void)putc(' ', pFile);
  786.             } else if (ucBytes[iCount] >= 0x80) {
  787.                 fprintf(pFile, "\\%03o", ucBytes[iCount]);
  788.             } else {
  789.                 (void)putc(szString[iCount], pFile);
  790.             }
  791.             break;
  792.         }
  793.     }
  794.     fprintf(pFile, ") ");
  795.     if (bIsStrike(ucFontstyle) && iFontsizeCurr > 0) {
  796.         fprintf(pFile, "%.2f %.2f LineShow\n",
  797.             iFontsizeCurr * 0.02, iFontsizeCurr * 0.12);
  798.     } else if (bIsUnderline(ucFontstyle) && iFontsizeCurr > 0) {
  799.         fprintf(pFile, "%.2f %.2f LineShow\n",
  800.             iFontsizeCurr * 0.02, iFontsizeCurr * -0.06);
  801.     } else {
  802.         fprintf(pFile, "show\n");
  803.     }
  804. } /* end of vPrintPS */
  805.  
  806. /*
  807.  * vSetColor - move to the given color
  808.  */
  809. static void
  810. vSetColor(FILE *pFile, int iColor)
  811. {
  812.     unsigned int    uiTmp, uiRed, uiGreen, uiBlue;
  813.  
  814.     uiTmp = uiColor2Color(iColor);
  815.     uiRed   = (uiTmp & 0x0000ff00) >> 8;
  816.     uiGreen = (uiTmp & 0x00ff0000) >> 16;
  817.     uiBlue  = (uiTmp & 0xff000000) >> 24;
  818.     fprintf(pFile, "%.3f %.3f %.3f setrgbcolor\n",
  819.                 uiRed / 255.0, uiGreen / 255.0, uiBlue / 255.0);
  820. } /* end of vSetColor */
  821.  
  822. /*
  823.  * vMoveToASCII - move to the given X,Y coordinates (ASCII)
  824.  *
  825.  * Move the current position of the given diagram to its X,Y coordinates,
  826.  * start on a new page if needed
  827.  */
  828. static void
  829. vMoveToASCII(diagram_type *pDiag)
  830. {
  831.     int    iCount, iNbr;
  832.  
  833.     fail(pDiag == NULL);
  834.     fail(pDiag->pOutFile == NULL);
  835.  
  836.     if (pDiag->lYtop != lYtopCurr) {
  837.         iNbr = iDrawUnits2Char(pDiag->lXleft);
  838.         for (iCount = 0; iCount < iNbr; iCount++) {
  839.             fprintf(pDiag->pOutFile, "%c", FILLER_CHAR);
  840.         }
  841.         lYtopCurr = pDiag->lYtop;
  842.     }
  843. } /* end of vMoveToASCII */
  844.  
  845. /*
  846.  * vMove2NextLine - move to the next line
  847.  */
  848. void
  849. vMove2NextLine(diagram_type *pDiag, draw_fontref tFontRef, int iFontsize)
  850. {
  851.     fail(pDiag == NULL);
  852.     fail(pDiag->pOutFile == NULL);
  853.     fail(iFontsize < MIN_FONT_SIZE || iFontsize > MAX_FONT_SIZE);
  854.  
  855.     pDiag->lYtop -= lComputeLeading(iFontsize);
  856.     if (!bUsePostScript) {
  857.         (void)fprintf(pDiag->pOutFile, "\n");
  858.     }
  859. } /* end of vMove2NextLine */
  860.  
  861. /*
  862.  * vSubstring2Diagram - put a sub string into a diagram
  863.  */
  864. void
  865. vSubstring2Diagram(diagram_type *pDiag,
  866.     char *szString, int iStringLength, long lStringWidth,
  867.     int iColor, unsigned char ucFontstyle, draw_fontref tFontRef,
  868.     int iFontsize, int iMaxFontsize)
  869. {
  870.     const char    *szOurFontname;
  871.  
  872.     fail(pDiag == NULL || szString == NULL);
  873.     fail(pDiag->pOutFile == NULL);
  874.     fail(pDiag->lXleft < 0);
  875.     fail(iStringLength < 0);
  876.     fail((size_t)iStringLength != strlen(szString));
  877.     fail(iFontsize < MIN_FONT_SIZE || iFontsize > MAX_FONT_SIZE);
  878.     fail(iMaxFontsize < MIN_FONT_SIZE || iMaxFontsize > MAX_FONT_SIZE);
  879.     fail(iFontsize > iMaxFontsize);
  880.  
  881.     if (szString[0] == '\0' || iStringLength <= 0) {
  882.         return;
  883.     }
  884.  
  885.     if (bUsePostScript) {
  886.         if (tFontRef != tFontRefCurr || iFontsize != iFontsizeCurr) {
  887.             szOurFontname = szGetFontname(tFontRef);
  888.             fail(szOurFontname == NULL);
  889.             fprintf(pDiag->pOutFile,
  890.                 "%.1f /%s /%s-ISO-8859-x ChgFnt\n",
  891.                 (double)iFontsize / 2.0,
  892.                 szOurFontname, szOurFontname);
  893.             tFontRefCurr = tFontRef;
  894.             iFontsizeCurr = iFontsize;
  895.         }
  896.         if (iColor != iColorCurr) {
  897.             vSetColor(pDiag->pOutFile, iColor);
  898.             iColorCurr = iColor;
  899.         }
  900.         vMoveToPS(pDiag, lComputeLeading(iMaxFontsize));
  901.         vPrintPS(pDiag->pOutFile, szString, iStringLength, ucFontstyle);
  902.     } else {
  903.         vMoveToASCII(pDiag);
  904.         fprintf(pDiag->pOutFile, "%.*s", iStringLength, szString);
  905.     }
  906.     pDiag->lXleft += lStringWidth;
  907. } /* end of vSubstring2Diagram */
  908.  
  909. /*
  910.  * Create an end of paragraph by moving the y-high mark 1/3 line down
  911.  */
  912. void
  913. vEndOfParagraph2Diagram(diagram_type *pDiag,
  914.             draw_fontref tFontRef, int iFontsize)
  915. {
  916.     fail(pDiag == NULL);
  917.     fail(pDiag->pOutFile == NULL);
  918.     fail(iFontsize < MIN_FONT_SIZE || iFontsize > MAX_FONT_SIZE);
  919.  
  920.     if (pDiag->lXleft > 0) {
  921.         /* To the start of the line */
  922.         vMove2NextLine(pDiag, tFontRef, iFontsize);
  923.     }
  924.     /* Empty line */
  925.     if (bUsePostScript) {
  926.         pDiag->lXleft = 0;
  927.         pDiag->lYtop -= lComputeLeading(iFontsize) / 3;
  928.     } else {
  929.         vMove2NextLine(pDiag, tFontRef, iFontsize);
  930.     }
  931. } /* end of vEndOfParagraph2Diagram */
  932.  
  933. /*
  934.  * Create an end of page
  935.  */
  936. void
  937. vEndOfPage2Diagram(diagram_type *pDiag,
  938.             draw_fontref tFontRef, int iFontsize)
  939. {
  940.     if (bUsePostScript) {
  941.         vMove2NextPage(pDiag);
  942.     } else {
  943.         vEndOfParagraph2Diagram(pDiag, tFontRef, iFontsize);
  944.     }
  945. } /* end of vEndOfPage2Diagram */
  946.