home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 720 / PDF090B4-SorceCode / pdf / PSOutputDev.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-30  |  31.2 KB  |  1,181 lines

  1. //========================================================================
  2. //
  3. // PSOutputDev.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. #pragma implementation
  11. #endif
  12.  
  13. #include <stdio.h>
  14. #include <stddef.h>
  15. #include <stdarg.h>
  16. #include <signal.h>
  17. #include <math.h>
  18. #include "GString.h"
  19. #include "config.h"
  20. #include "Object.h"
  21. #include "Error.h"
  22. #include "GfxState.h"
  23. #include "GfxFont.h"
  24. #include "FontFile.h"
  25. #include "Catalog.h"
  26. #include "Page.h"
  27. #include "Stream.h"
  28. #include "PSOutputDev.h"
  29.  
  30. //------------------------------------------------------------------------
  31. // Parameters
  32. //------------------------------------------------------------------------
  33.  
  34. // Generate Level 1 PostScript?
  35. GBool psOutLevel1 = gFalse;
  36.  
  37. int paperWidth = defPaperWidth;
  38. int paperHeight = defPaperHeight;
  39.  
  40. //------------------------------------------------------------------------
  41. // PostScript prolog and setup
  42. //------------------------------------------------------------------------
  43.  
  44. static char *prolog[] = {
  45.   "/xpdf 75 dict def xpdf begin",
  46.   "% PDF special state",
  47.   "/pdfDictSize 14 def",
  48.   "/pdfSetup {",
  49.   "  2 array astore",
  50.   "  /setpagedevice where {",
  51.   "    pop 3 dict dup begin",
  52.   "      exch /PageSize exch def",
  53.   "      /ImagingBBox null def",
  54.   "      /Policies 1 dict dup begin /PageSize 3 def end def",
  55.   "    end setpagedevice",
  56.   "  } {",
  57.   "    pop",
  58.   "  } ifelse",
  59.   "} def",
  60.   "/pdfStartPage {",
  61.   "  pdfDictSize dict begin",
  62.   "  /pdfFill [0] def",
  63.   "  /pdfStroke [0] def",
  64.   "  /pdfLastFill false def",
  65.   "  /pdfLastStroke false def",
  66.   "  /pdfTextMat [1 0 0 1 0 0] def",
  67.   "  /pdfFontSize 0 def",
  68.   "  /pdfCharSpacing 0 def",
  69.   "  /pdfTextRender 0 def",
  70.   "  /pdfTextRise 0 def",
  71.   "  /pdfWordSpacing 0 def",
  72.   "  /pdfHorizScaling 1 def",
  73.   "} def",
  74.   "/pdfEndPage { end } def",
  75.   "/sCol { pdfLastStroke not {",
  76.   "          pdfStroke aload length",
  77.   "          1 eq { setgray } { setrgbcolor} ifelse",
  78.   "          /pdfLastStroke true def /pdfLastFill false def",
  79.   "        } if } def",
  80.   "/fCol { pdfLastFill not {",
  81.   "          pdfFill aload length",
  82.   "          1 eq { setgray } { setrgbcolor } ifelse",
  83.   "          /pdfLastFill true def /pdfLastStroke false def",
  84.   "        } if } def",
  85.   "% build a font",
  86.   "/pdfMakeFont {",
  87.   "  3 2 roll findfont",
  88.   "  3 2 roll 1 matrix scale makefont",
  89.   "  dup length dict begin",
  90.   "    { 1 index /FID ne { def } { pop pop } ifelse } forall",
  91.   "    /Encoding exch def",
  92.   "    currentdict",
  93.   "  end",
  94.   "  definefont pop",
  95.   "} def",
  96.   "% graphics state operators",
  97.   "/q { gsave pdfDictSize dict begin } def",
  98.   "/Q { end grestore } def",
  99.   "/cm { concat } def",
  100.   "/d { setdash } def",
  101.   "/i { setflat } def",
  102.   "/j { setlinejoin } def",
  103.   "/J { setlinecap } def",
  104.   "/M { setmiterlimit } def",
  105.   "/w { setlinewidth } def",
  106.   "% color operators",
  107.   "/g { dup 1 array astore /pdfFill exch def setgray",
  108.   "    /pdfLastFill true def /pdfLastStroke false def } def",
  109.   "/G { dup 1 array astore /pdfStroke exch def setgray",
  110.   "     /pdfLastStroke true def /pdfLastFill false def } def",
  111.   "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
  112.   "     /pdfLastFill true def /pdfLastStroke false def } def",
  113.   "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
  114.   "     /pdfLastStroke true def /pdfLastFill false def } def",
  115.   "% path segment operators",
  116.   "/m { moveto } def",
  117.   "/l { lineto } def",
  118.   "/c { curveto } def",
  119.   "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
  120.   "      neg 0 rlineto closepath } def",
  121.   "% path painting operators",
  122.   "/S { sCol stroke } def",
  123.   "/f { fCol fill } def",
  124.   "/f* { fCol eofill } def",
  125.   "% clipping operators",
  126.   "/W { clip newpath } def",
  127.   "/W* { eoclip newpath } def",
  128.   "% text state operators",
  129.   "/Tc { /pdfCharSpacing exch def } def",
  130.   "/Tf { dup /pdfFontSize exch def",
  131.   "      dup pdfHorizScaling mul exch matrix scale",
  132.   "      pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
  133.   "      exch findfont exch makefont setfont } def",
  134.   "/Tr { /pdfTextRender exch def } def",
  135.   "/Ts { /pdfTextRise exch def } def",
  136.   "/Tw { /pdfWordSpacing exch def } def",
  137.   "/Tz { /pdfHorizScaling exch def } def",
  138.   "% text positioning operators",
  139.   "/Td { pdfTextMat transform moveto } def",
  140.   "/Tm { /pdfTextMat exch def } def",
  141.   "% text string operators",
  142.   "/Tj { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
  143.   "      0 pdfTextRise pdfTextMat dtransform rmoveto",
  144.   "      pdfFontSize mul pdfHorizScaling mul",
  145.   "      1 index stringwidth pdfTextMat idtransform pop",
  146.   "      sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
  147.   "      pdfWordSpacing 0 pdfTextMat dtransform 32",
  148.   "      4 3 roll pdfCharSpacing add 0 pdfTextMat dtransform",
  149.   "      6 5 roll awidthshow",
  150.   "      0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
  151.   "/TJm { pdfFontSize 0.001 mul mul neg 0",
  152.   "       pdfTextMat dtransform rmoveto } def",
  153.   "% Level 1 image operators",
  154.   "/pdfIm1 {",
  155.   "  /pdfImBuf1 4 index string def",
  156.   "  { currentfile pdfImBuf1 readhexstring pop } image",
  157.   "} def",
  158.   "/pdfImM1 {",
  159.   "  /pdfImBuf1 4 index 7 add 8 idiv string def",
  160.   "  { currentfile pdfImBuf1 readhexstring pop } imagemask",
  161.   "} def",
  162.   "% Level 2 image operators",
  163.   "/pdfImBuf 100 string def",
  164.   "/pdfIm {",
  165.   "  image",
  166.   "  { currentfile pdfImBuf readline",
  167.   "    not { pop exit } if",
  168.   "    (%-EOD-) eq { exit } if } loop",
  169.   "} def",
  170.   "/pdfImM {",
  171.   "  fCol imagemask",
  172.   "  { currentfile pdfImBuf readline",
  173.   "    not { pop exit } if",
  174.   "    (%-EOD-) eq { exit } if } loop",
  175.   "} def",
  176.   "end",
  177.   NULL
  178. };
  179.  
  180. //------------------------------------------------------------------------
  181. // Fonts
  182. //------------------------------------------------------------------------
  183.  
  184. struct PSFont {
  185.   char *name;            // PDF name
  186.   char *psName;            // PostScript name
  187. };
  188.  
  189. struct PSSubstFont {
  190.   char *psName;            // PostScript name
  191.   double mWidth;        // width of 'm' character
  192. };
  193.  
  194. static PSFont psFonts[] = {
  195.   {"Courier",               "Courier"},
  196.   {"Courier-Bold",          "Courier-Bold"},
  197.   {"Courier-Oblique",       "Courier-Bold"},
  198.   {"Courier-BoldOblique",   "Courier-BoldOblique"},
  199.   {"Helvetica",             "Helvetica"},
  200.   {"Helvetica-Bold",        "Helvetica-Bold"},
  201.   {"Helvetica-Oblique",     "Helvetica-Oblique"},
  202.   {"Helvetica-BoldOblique", "Helvetica-BoldOblique"},
  203.   {"Symbol",                "Symbol"},
  204.   {"Times-Roman",           "Times-Roman"},
  205.   {"Times-Bold",            "Times-Bold"},
  206.   {"Times-Italic",          "Times-Italic"},
  207.   {"Times-BoldItalic",      "Times-BoldItalic"},
  208.   {"ZapfDingbats",          "ZapfDingbats"},
  209.   {NULL}
  210. };
  211.  
  212. static PSSubstFont psSubstFonts[] = {
  213.   {"Helvetica",             0.833},
  214.   {"Helvetica-Oblique",     0.833},
  215.   {"Helvetica-Bold",        0.889},
  216.   {"Helvetica-BoldOblique", 0.889},
  217.   {"Times-Roman",           0.788},
  218.   {"Times-Italic",          0.722},
  219.   {"Times-Bold",            0.833},
  220.   {"Times-BoldItalic",      0.778},
  221.   {"Courier",               0.600},
  222.   {"Courier-Oblique",       0.600},
  223.   {"Courier-Bold",          0.600},
  224.   {"Courier-BoldOblique",   0.600}
  225. };
  226.  
  227. //------------------------------------------------------------------------
  228. // PSOutputDev
  229. //------------------------------------------------------------------------
  230.  
  231. PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog,
  232.              int firstPage, int lastPage,
  233.              GBool embedType11, GBool doForm1) {
  234.   Page *page;
  235.   Dict *resDict;
  236.   char **p;
  237.   int pg;
  238.  
  239.   // initialize
  240.   embedType1 = embedType11;
  241.   doForm = doForm1;
  242.   fontIDs = NULL;
  243.   fontFileIDs = NULL;
  244.   fontFileNames = NULL;
  245.   f = NULL;
  246.   if (doForm)
  247.     lastPage = firstPage;
  248.  
  249.   // open file or pipe
  250.   ok = gTrue;
  251.   if (!strcmp(fileName, "-")) {
  252.     fileType = psStdout;
  253.     f = stdout;
  254.   } else if (fileName[0] == '|') {
  255.     fileType = psPipe;
  256. #ifdef HAVE_POPEN
  257. #ifndef WIN32
  258.     signal(SIGPIPE, (void (*)(int))SIG_IGN);
  259. #endif
  260.     if (!(f = popen(fileName + 1, "w"))) {
  261.       error(-1, "Couldn't run print command '%s'", fileName);
  262.       ok = gFalse;
  263.       return;
  264.     }
  265. #else
  266.     error(-1, "Print commands are not supported ('%s')", fileName);
  267.     ok = gFalse;
  268.     return;
  269. #endif
  270.   } else {
  271.     fileType = psFile;
  272.     if (!(f = fopen(fileName, "w"))) {
  273.       error(-1, "Couldn't open PostScript file '%s'", fileName);
  274.       ok = gFalse;
  275.       return;
  276.     }
  277.   }
  278.  
  279.   // initialize fontIDs, fontFileIDs, and fontFileNames lists
  280.   fontIDSize = 64;
  281.   fontIDLen = 0;
  282.   fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
  283.   fontFileIDSize = 64;
  284.   fontFileIDLen = 0;
  285.   fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
  286.   fontFileNameSize = 64;
  287.   fontFileNameLen = 0;
  288.   fontFileNames = (char **)gmalloc(fontFileNameSize * sizeof(char *));
  289.  
  290.   // write header
  291.   if (doForm) {
  292.     writePS("%%!PS-Adobe-3.0 Resource-Form\n");
  293.     writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
  294.     writePS("%%%%EndComments\n");
  295.   } else {
  296.     writePS("%%!PS-Adobe-3.0\n");
  297.     writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
  298.     writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
  299.     writePS("%%%%EndComments\n");
  300.   }
  301.  
  302.   // write prolog
  303.   if (!doForm)
  304.     writePS("%%%%BeginProlog\n");
  305.   writePS("%%%%BeginResource: xpdf %s\n", xpdfVersion);
  306.   for (p = prolog; *p; ++p)
  307.     writePS("%s\n", *p);
  308.   writePS("%%%%EndResource\n");
  309.   if (!doForm)
  310.     writePS("%%%%EndProlog\n");
  311.  
  312.   // set up fonts
  313.   if (!doForm)
  314.     writePS("%%%%BeginSetup\n");
  315.   writePS("xpdf begin\n");
  316.   for (pg = firstPage; pg <= lastPage; ++pg) {
  317.     if ((resDict = catalog->getPage(pg)->getResourceDict()))
  318.       setupFonts(resDict);
  319.   }
  320.   if (doForm) {
  321.     writePS("end\n");
  322.   } else {
  323.     writePS("%d %d pdfSetup\n", paperWidth, paperHeight);
  324.     writePS("%%%%EndSetup\n");
  325.   }
  326.  
  327.   // write form header
  328.   if (doForm) {
  329.     page = catalog->getPage(firstPage);
  330.     writePS("4 dict dup begin\n");
  331.     writePS("/BBox [%d %d %d %d] def\n",
  332.         (int)page->getX1(), (int)page->getY1(),
  333.         (int)page->getX2(), (int)page->getY2());
  334.     writePS("/FormType 1 def\n");
  335.     writePS("/Matrix [1 0 0 1 0 0] def\n");
  336.   }
  337.  
  338.   // initialize sequential page number
  339.   seqPage = 1;
  340. }
  341.  
  342. PSOutputDev::~PSOutputDev() {
  343.   if (f) {
  344.     if (doForm) {
  345.       writePS("end\n");
  346.       writePS("/Foo exch /Form defineresource pop\n");
  347.     } else {
  348.       writePS("%%%%Trailer\n");
  349.       writePS("end\n");
  350.       writePS("%%%%EOF\n");
  351.     }
  352.     if (fileType == psFile) {
  353.       fclose(f);
  354.     }
  355. #ifdef HAVE_POPEN
  356.     else if (fileType == psPipe) {
  357.       pclose(f);
  358. #ifndef WIN32
  359.       signal(SIGPIPE, (void (*)(int))SIG_DFL);
  360. #endif
  361.     }
  362. #endif
  363.   }
  364.   if (fontIDs)
  365.     gfree(fontIDs);
  366.   if (fontFileIDs)
  367.     gfree(fontFileIDs);
  368.   if (fontFileNames)
  369.     gfree(fontFileNames);
  370. }
  371.  
  372. void PSOutputDev::setupFonts(Dict *resDict) {
  373.   Object fontDict, xObjDict, xObj, resObj;
  374.   GfxFontDict *gfxFontDict;
  375.   GfxFont *font;
  376.   int i;
  377.  
  378.   resDict->lookup("Font", &fontDict);
  379.   if (fontDict.isDict()) {
  380.     gfxFontDict = new GfxFontDict();
  381.     gfxFontDict->ConstructL(fontDict.getDict());
  382.     for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
  383.       font = gfxFontDict->getFont(i);
  384.       setupFont(font);
  385.     }
  386.     delete gfxFontDict;
  387.   }
  388.   fontDict.free();
  389.  
  390.   resDict->lookup("XObject", &xObjDict);
  391.   if (xObjDict.isDict()) {
  392.     for (i = 0; i < xObjDict.dictGetLength(); ++i) {
  393.       xObjDict.dictGetVal(i, &xObj);
  394.       if (xObj.isStream()) {
  395.     xObj.streamGetDict()->lookup("Resources", &resObj);
  396.     if (resObj.isDict())
  397.       setupFonts(resObj.getDict());
  398.     resObj.free();
  399.       }
  400.       xObj.free();
  401.     }
  402.   }
  403.   xObjDict.free();
  404. }
  405.  
  406. void PSOutputDev::setupFont(GfxFont *font) {
  407.   Ref fontFileID;
  408.   GString *name;
  409.   char *psName;
  410.   char *charName;
  411.   double scale;
  412.   int i, j;
  413.  
  414.   // check if font is already set up
  415.   for (i = 0; i < fontIDLen; ++i) {
  416.     if (fontIDs[i].num == font->getID().num &&
  417.     fontIDs[i].gen == font->getID().gen)
  418.       return;
  419.   }
  420.  
  421.   // add entry to fontIDs list
  422.   if (fontIDLen >= fontIDSize) {
  423.     fontIDSize += 64;
  424.     fontIDs = (Ref *)gser::ReAllocL(fontIDs, fontIDSize * sizeof(Ref));
  425.   }
  426.   fontIDs[fontIDLen++] = font->getID();
  427.  
  428.   // check for embedded Type 1 font
  429.   if (embedType1 && font->getType() == fontType1 &&
  430.       font->getEmbeddedFontID(&fontFileID)) {
  431.     setupEmbeddedType1Font(&fontFileID);
  432.     psName = font->getEmbeddedFontName();
  433.     scale = 1;
  434.  
  435.   // check for external Type 1 font file
  436.   } else if (embedType1 && font->getType() == fontType1 &&
  437.          font->getExtFontFile()) {
  438.     setupEmbeddedType1Font(font->getExtFontFile());
  439.     // this assumes that the PS font name matches the PDF font name
  440.     psName = font->getName()->getCString();
  441.     scale = 1;
  442.  
  443.   // check for embedded Type 1C font
  444.   } else if (embedType1 && font->getType() == fontType1C &&
  445.          font->getEmbeddedFontID(&fontFileID)) {
  446.     setupEmbeddedType1CFont(font, &fontFileID);
  447.     psName = font->getEmbeddedFontName();
  448.     scale = 1;
  449.  
  450.   // do font substitution
  451.   } else {
  452.     name = font->getName();
  453.     psName = NULL;
  454.     scale = 1.0;
  455.     if (name) {
  456.       for (i = 0; psFonts[i].name; ++i) {
  457.     if (name->cmp(psFonts[i].name) == 0) {
  458.       psName = psFonts[i].psName;
  459.       break;
  460.     }
  461.       }
  462.     }
  463.     if (!psName) {
  464.       if (font->isFixedWidth())
  465.     i = 8;
  466.       else if (font->isSerif())
  467.     i = 4;
  468.       else
  469.     i = 0;
  470.       if (font->isBold())
  471.     i += 2;
  472.       if (font->isItalic())
  473.     i += 1;
  474.       psName = psSubstFonts[i].psName;
  475.       scale = font->getWidth('m') / psSubstFonts[i].mWidth;
  476.       if (scale < 0.1)
  477.     scale = 1;
  478.     }
  479.   }
  480.  
  481.   // generate PostScript code to set up the font
  482.   writePS("/F%d_%d /%s %g\n",
  483.       font->getID().num, font->getID().gen, psName, scale);
  484.   for (i = 0; i < 256; i += 8) {
  485.     writePS((i == 0) ? "[ " : "  ");
  486.     for (j = 0; j < 8; ++j) {
  487.       charName = font->getCharName(i+j);
  488.       writePS("/%s", charName ? charName : ".notdef");
  489.     }
  490.     writePS((i == 256-8) ? "]\n" : "\n");
  491.   }
  492.   writePS("pdfMakeFont\n");
  493. }
  494.  
  495. void PSOutputDev::setupEmbeddedType1Font(Ref *id) {
  496.   static char hexChar[17] = "0123456789abcdef";
  497.   Object refObj, strObj, obj1, obj2;
  498.   Dict *dict;
  499.   int length1, length2;
  500.   int c;
  501.   int start[4];
  502.   GBool binMode;
  503.   int i;
  504.  
  505.   // check if font is already embedded
  506.   for (i = 0; i < fontFileIDLen; ++i) {
  507.     if (fontFileIDs[i].num == id->num &&
  508.     fontFileIDs[i].gen == id->gen)
  509.       return;
  510.   }
  511.  
  512.   // add entry to fontFileIDs list
  513.   if (fontFileIDLen >= fontFileIDSize) {
  514.     fontFileIDSize += 64;
  515.     fontFileIDs = (Ref *)User::ReAllocL(fontFileIDs, fontFileIDSize * sizeof(Ref));
  516.   }
  517.   fontFileIDs[fontFileIDLen++] = *id;
  518.  
  519.   // get the font stream and info
  520.   refObj.initRef(id->num, id->gen);
  521.   refObj.fetch(&strObj);
  522.   refObj.free();
  523.   if (!strObj.isStream()) {
  524.     error(-1, "Embedded font file object is not a stream");
  525.     goto err1;
  526.   }
  527.   if (!(dict = strObj.streamGetDict())) {
  528.     error(-1, "Embedded font stream is missing its dictionary");
  529.     goto err1;
  530.   }
  531.   dict->lookup("Length1", &obj1);
  532.   dict->lookup("Length2", &obj2);
  533.   if (!obj1.isInt() || !obj2.isInt()) {
  534.     error(-1, "Missing length fields in embedded font stream dictionary");
  535.     obj1.free();
  536.     obj2.free();
  537.     goto err1;
  538.   }
  539.   length1 = obj1.getInt();
  540.   length2 = obj2.getInt();
  541.   obj1.free();
  542.   obj2.free();
  543.  
  544.   // copy ASCII portion of font
  545.   strObj.streamReset();
  546.   for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i)
  547.     fputc(c, f);
  548.  
  549.   // figure out if encrypted portion is binary or ASCII
  550.   binMode = gFalse;
  551.   for (i = 0; i < 4; ++i) {
  552.     start[i] = strObj.streamGetChar();
  553.     if (start[i] == EOF) {
  554.       error(-1, "Unexpected end of file in embedded font stream");
  555.       goto err1;
  556.     }
  557.     if (!((start[i] >= '0' && start[i] <= '9') ||
  558.       (start[i] >= 'A' && start[i] <= 'F') ||
  559.       (start[i] >= 'a' && start[i] <= 'f')))
  560.       binMode = gTrue;
  561.   }
  562.  
  563.   // convert binary data to ASCII
  564.   if (binMode) {
  565.     for (i = 0; i < 4; ++i) {
  566.       fputc(hexChar[(start[i] >> 4) & 0x0f], f);
  567.       fputc(hexChar[start[i] & 0x0f], f);
  568.     }
  569.     while (i < length2) {
  570.       if ((c = strObj.streamGetChar()) == EOF)
  571.     break;
  572.       fputc(hexChar[(c >> 4) & 0x0f], f);
  573.       fputc(hexChar[c & 0x0f], f);
  574.       if (++i % 32 == 0)
  575.     fputc('\n', f);
  576.     }
  577.     if (i % 32 > 0)
  578.       fputc('\n', f);
  579.  
  580.   // already in ASCII format -- just copy it
  581.   } else {
  582.     for (i = 0; i < 4; ++i)
  583.       fputc(start[i], f);
  584.     for (i = 4; i < length2; ++i) {
  585.       if ((c = strObj.streamGetChar()) == EOF)
  586.     break;
  587.       fputc(c, f);
  588.     }
  589.   }
  590.  
  591.   // write padding and "cleartomark"
  592.   for (i = 0; i < 8; ++i)
  593.     writePS("00000000000000000000000000000000"
  594.         "00000000000000000000000000000000\n");
  595.   writePS("cleartomark\n");
  596.  
  597.  err1:
  598.   strObj.free();
  599. }
  600.  
  601. //~ This doesn't handle .pfb files or binary eexec data (which only
  602. //~ happens in pfb files?).
  603. void PSOutputDev::setupEmbeddedType1Font(char *fileName) {
  604.   FILE *fontFile;
  605.   int c;
  606.   int i;
  607.  
  608.   // check if font is already embedded
  609.   for (i = 0; i < fontFileNameLen; ++i) {
  610.     if (!strcmp(fontFileNames[i], fileName))
  611.       return;
  612.   }
  613.  
  614.   // add entry to fontFileNames list
  615.   if (fontFileNameLen >= fontFileNameSize) {
  616.     fontFileNameSize += 64;
  617.     fontFileNames = (char **)User::reAllocL(fontFileNames,
  618.                       fontFileNameSize * sizeof(char *));
  619.   }
  620.   fontFileNames[fontFileNameLen++] = fileName;
  621.  
  622.   // copy the font file
  623.   if (!(fontFile = fopen(fileName, "rb"))) {
  624.     error(-1, "Couldn't open external font file");
  625.     return;
  626.   }
  627.   while ((c = fgetc(fontFile)) != EOF)
  628.     fputc(c, f);
  629.   fclose(fontFile);
  630. }
  631.  
  632. void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id) {
  633.   char *fontBuf;
  634.   int fontLen;
  635.   Type1CFontConverter *cvt;
  636.   int i;
  637.  
  638.   // check if font is already embedded
  639.   for (i = 0; i < fontFileIDLen; ++i) {
  640.     if (fontFileIDs[i].num == id->num &&
  641.     fontFileIDs[i].gen == id->gen)
  642.       return;
  643.   }
  644.  
  645.   // add entry to fontFileIDs list
  646.   if (fontFileIDLen >= fontFileIDSize) {
  647.     fontFileIDSize += 64;
  648.     fontFileIDs = (Ref *)User::ReAllocL(fontFileIDs, fontFileIDSize * sizeof(Ref));
  649.   }
  650.   fontFileIDs[fontFileIDLen++] = *id;
  651.  
  652.   // convert it to a Type 1 font
  653.   fontBuf = font->readEmbFontFile(&fontLen);
  654.   cvt = new Type1CFontConverter(fontBuf, fontLen, f);
  655.   cvt->convert();
  656.   delete cvt;
  657.   gfree(fontBuf);
  658. }
  659.  
  660. void PSOutputDev::startPage(int pageNum, GfxState *state) {
  661.   int x1, y1, x2, y2, width, height, t;
  662.   double xScale, yScale;
  663.  
  664.   if (doForm) {
  665.  
  666.     writePS("/PaintProc {\n");
  667.     writePS("begin xpdf begin\n");
  668.     writePS("pdfSetup\n");
  669.  
  670.   } else {
  671.  
  672.     writePS("%%%%Page: %d %d\n", pageNum, seqPage);
  673.     writePS("%%%%BeginPageSetup\n");
  674.  
  675.     // rotate, translate, and scale page
  676.     x1 = (int)(state->getX1() + 0.5);
  677.     y1 = (int)(state->getY1() + 0.5);
  678.     x2 = (int)(state->getX2() + 0.5);
  679.     y2 = (int)(state->getY2() + 0.5);
  680.     width = x2 - x1;
  681.     height = y2 - y1;
  682.     if (width > height) {
  683.       writePS("%%%%PageOrientation: Landscape\n");
  684.       writePS("pdfStartPage\n");
  685.       writePS("90 rotate\n");
  686.       writePS("%d %d translate\n", -x1, -(y1 + paperWidth));
  687.       t = width;
  688.       width = height;
  689.       height = t;
  690.     } else {
  691.       writePS("%%%%PageOrientation: Portrait\n");
  692.       writePS("pdfStartPage\n");
  693.       if (x1 != 0 || y1 != 0)
  694.     writePS("%d %d translate\n", -x1, -y1);
  695.     }
  696.     if (width > paperWidth || height > paperHeight) {
  697.       xScale = (double)paperWidth / (double)width;
  698.       yScale = (double)paperHeight / (double)height;
  699.       if (yScale < xScale)
  700.     xScale = yScale;
  701.       writePS("%0.4f %0.4f scale\n", xScale, xScale);
  702.     }
  703.  
  704.     writePS("%%%%EndPageSetup\n");
  705.     ++seqPage;
  706.   }
  707. }
  708.  
  709. void PSOutputDev::endPage() {
  710.   if (doForm) {
  711.     writePS("pdfEndPage\n");
  712.     writePS("end end\n");
  713.     writePS("} def\n");
  714.   } else {
  715.     writePS("showpage\n");
  716.     writePS("%%%%PageTrailer\n");
  717.     writePS("pdfEndPage\n");
  718.   }
  719. }
  720.  
  721. void PSOutputDev::saveState(GfxState *state) {
  722.   writePS("q\n");
  723. }
  724.  
  725. void PSOutputDev::restoreState(GfxState *state) {
  726.   writePS("Q\n");
  727. }
  728.  
  729. void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
  730.                 double m21, double m22, double m31, double m32) {
  731.   writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
  732. }
  733.  
  734. void PSOutputDev::updateLineDash(GfxState *state) {
  735.   double *dash;
  736.   double start;
  737.   int length, i;
  738.  
  739.   state->getLineDash(&dash, &length, &start);
  740.   writePS("[");
  741.   for (i = 0; i < length; ++i)
  742.     writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
  743.   writePS("] %g d\n", start);
  744. }
  745.  
  746. void PSOutputDev::updateFlatness(GfxState *state) {
  747.   writePS("%d i\n", state->getFlatness());
  748. }
  749.  
  750. void PSOutputDev::updateLineJoin(GfxState *state) {
  751.   writePS("%d j\n", state->getLineJoin());
  752. }
  753.  
  754. void PSOutputDev::updateLineCap(GfxState *state) {
  755.   writePS("%d J\n", state->getLineCap());
  756. }
  757.  
  758. void PSOutputDev::updateMiterLimit(GfxState *state) {
  759.   writePS("%g M\n", state->getMiterLimit());
  760. }
  761.  
  762. void PSOutputDev::updateLineWidth(GfxState *state) {
  763.   writePS("%g w\n", state->getLineWidth());
  764. }
  765.  
  766. void PSOutputDev::updateFillColor(GfxState *state) {
  767.   GfxColor *color;
  768.   double r, g, b;
  769.  
  770.   color = state->getFillColor();
  771.   r = color->getR();
  772.   g = color->getG();
  773.   b = color->getB();
  774.   if (r == g && g == b)
  775.     writePS("%g g\n", r);
  776.   else
  777.     writePS("%g %g %g rg\n", r, g, b);
  778. }
  779.  
  780. void PSOutputDev::updateStrokeColor(GfxState *state) {
  781.   GfxColor *color;
  782.   double r, g, b;
  783.  
  784.   color = state->getStrokeColor();
  785.   r = color->getR();
  786.   g = color->getG();
  787.   b = color->getB();
  788.   if (r == g && g == b)
  789.     writePS("%g G\n", r);
  790.   else
  791.     writePS("%g %g %g RG\n", r, g, b);
  792. }
  793.  
  794. void PSOutputDev::updateFont(GfxState *state) {
  795.   if (state->getFont()) {
  796.     writePS("/F%d_%d %g Tf\n",
  797.         state->getFont()->getID().num, state->getFont()->getID().gen,
  798.         state->getFontSize());
  799.   }
  800. }
  801.  
  802. void PSOutputDev::updateTextMat(GfxState *state) {
  803.   double *mat;
  804.  
  805.   mat = state->getTextMat();
  806.   writePS("[%g %g %g %g %g %g] Tm\n",
  807.       mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
  808. }
  809.  
  810. void PSOutputDev::updateCharSpace(GfxState *state) {
  811.   writePS("%g Tc\n", state->getCharSpace());
  812. }
  813.  
  814. void PSOutputDev::updateRender(GfxState *state) {
  815.   writePS("%d Tr\n", state->getRender());
  816. }
  817.  
  818. void PSOutputDev::updateRise(GfxState *state) {
  819.   writePS("%g Ts\n", state->getRise());
  820. }
  821.  
  822. void PSOutputDev::updateWordSpace(GfxState *state) {
  823.   writePS("%g Tw\n", state->getWordSpace());
  824. }
  825.  
  826. void PSOutputDev::updateHorizScaling(GfxState *state) {
  827.   writePS("%g Tz\n", state->getHorizScaling());
  828. }
  829.  
  830. void PSOutputDev::updateTextPos(GfxState *state) {
  831.   writePS("%g %g Td\n", state->getLineX(), state->getLineY());
  832. }
  833.  
  834. void PSOutputDev::updateTextShift(GfxState *state, double shift) {
  835.   writePS("%g TJm\n", shift);
  836. }
  837.  
  838. void PSOutputDev::stroke(GfxState *state) {
  839.   doPath(state->getPath());
  840.   writePS("S\n");
  841. }
  842.  
  843. void PSOutputDev::fill(GfxState *state, GBool strokeToo) {
  844.   doPath(state->getPath());
  845.   writePS("f\n");
  846.   if (strokeToo)
  847.     stroke(state);
  848. }
  849.  
  850. void PSOutputDev::eoFill(GfxState *state, GBool strokeToo) {
  851.   doPath(state->getPath());
  852.   writePS("f*\n");
  853.   if (strokeToo)
  854.     stroke(state);
  855. }
  856.  
  857. void PSOutputDev::clip(GfxState *state) {
  858.   doPath(state->getPath());
  859.   writePS("W\n");
  860. }
  861.  
  862. void PSOutputDev::eoClip(GfxState *state) {
  863.   doPath(state->getPath());
  864.   writePS("W*\n");
  865. }
  866.  
  867. void PSOutputDev::doPath(GfxPath *path) {
  868.   GfxSubpath *subpath;
  869.   double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
  870.   int n, m, i, j;
  871.  
  872.   n = path->getNumSubpaths();
  873.  
  874.   if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
  875.     subpath = path->getSubpath(0);
  876.     x0 = subpath->getX(0);
  877.     y0 = subpath->getY(0);
  878.     x4 = subpath->getX(4);
  879.     y4 = subpath->getY(4);
  880.     if (x4 == x0 && y4 == y0) {
  881.       x1 = subpath->getX(1);
  882.       y1 = subpath->getY(1);
  883.       x2 = subpath->getX(2);
  884.       y2 = subpath->getY(2);
  885.       x3 = subpath->getX(3);
  886.       y3 = subpath->getY(3);
  887.       if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
  888.     writePS("%g %g %g %g re\n",
  889.         x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
  890.         fabs(x2 - x0), fabs(y1 - y0));
  891.     return;
  892.       } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
  893.     writePS("%g %g %g %g re\n",
  894.         x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
  895.         fabs(x1 - x0), fabs(y2 - y0));
  896.     return;
  897.       }
  898.     }
  899.   }
  900.  
  901.   for (i = 0; i < n; ++i) {
  902.     subpath = path->getSubpath(i);
  903.     m = subpath->getNumPoints();
  904.     writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
  905.     j = 1;
  906.     while (j < m) {
  907.       if (subpath->getCurve(j)) {
  908.     writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
  909.         subpath->getX(j+1), subpath->getY(j+1),
  910.         subpath->getX(j+2), subpath->getY(j+2));
  911.     j += 3;
  912.       } else {
  913.     writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
  914.     ++j;
  915.       }
  916.     }
  917.   }
  918. }
  919.  
  920. void PSOutputDev::drawString(GfxState *state, GString *s) {
  921.   // check for invisible text -- this is used by Acrobat Capture
  922.   if ((state->getRender() & 3) == 3)
  923.     return;
  924.  
  925.   writePSString(s);
  926.   writePS(" %g Tj\n", state->getFont()->getWidth(s));
  927. }
  928.  
  929. void PSOutputDev::drawImageMask(GfxState *state, Stream *str,
  930.                 int width, int height, GBool invert,
  931.                 GBool inlineImg) {
  932.   int len;
  933.  
  934.   len = height * ((width + 7) / 8);
  935.   if (psOutLevel1)
  936.     doImageL1(NULL, invert, inlineImg, str, width, height, len);
  937.   else
  938.     doImage(NULL, invert, inlineImg, str, width, height, len);
  939. }
  940.  
  941. void PSOutputDev::drawImage(GfxState *state, Stream *str, int width,
  942.                 int height, GfxImageColorMap *colorMap,
  943.                 GBool inlineImg) {
  944.   int len;
  945.  
  946.   len = height * ((width * colorMap->getNumPixelComps() *
  947.            colorMap->getBits() + 7) / 8);
  948.   if (psOutLevel1)
  949.     doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
  950.   else
  951.     doImage(colorMap, gFalse, inlineImg, str, width, height, len);
  952. }
  953.  
  954. void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
  955.                 GBool invert, GBool inlineImg,
  956.                 Stream *str, int width, int height, int len) {
  957.   ImageStream *imgStr;
  958.   Guchar pixBuf[4];
  959.   GfxColor color;
  960.   int x, y, i;
  961.  
  962.   // width, height, matrix, bits per component
  963.   if (colorMap) {
  964.     writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
  965.         width, height,
  966.         width, -height, height);
  967.   } else {
  968.     writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
  969.         width, height, invert ? "true" : "false",
  970.         width, -height, height);
  971.   }
  972.  
  973.   // image
  974.   if (colorMap) {
  975.  
  976.     // set up to process the data stream
  977.     imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
  978.                  colorMap->getBits());
  979.     imgStr->ConstructL();
  980.     imgStr->reset();
  981.  
  982.     // process the data stream
  983.     i = 0;
  984.     for (y = 0; y < height; ++y) {
  985.  
  986.       // write the line
  987.       for (x = 0; x < width; ++x) {
  988.     imgStr->getPixel(pixBuf);
  989.     colorMap->getColor(pixBuf, &color);
  990.     fprintf(f, "%02x", (int)(color.getGray() * 255 + 0.5));
  991.     if (++i == 32) {
  992.       fputc('\n', f);
  993.       i = 0;
  994.     }
  995.       }
  996.     }
  997.     if (i != 0)
  998.       fputc('\n', f);
  999.     delete imgStr;
  1000.  
  1001.   // imagemask
  1002.   } else {
  1003.     str->reset();
  1004.     i = 0;
  1005.     for (y = 0; y < height; ++y) {
  1006.       for (x = 0; x < width; x += 8) {
  1007.     fprintf(f, "%02x", str->getChar() & 0xff);
  1008.     if (++i == 32) {
  1009.       fputc('\n', f);
  1010.       i = 0;
  1011.     }
  1012.       }
  1013.     }
  1014.     if (i != 0)
  1015.       fputc('\n', f);
  1016.   }
  1017. }
  1018.  
  1019. void PSOutputDev::doImage(GfxImageColorMap *colorMap,
  1020.               GBool invert, GBool inlineImg,
  1021.               Stream *str, int width, int height, int len) {
  1022.   GfxColorSpace *colorSpace;
  1023.   GString *s;
  1024.   int n, numComps;
  1025.   Guchar *color;
  1026.   GBool useRLE, useA85;
  1027.   int c;
  1028.   int i, j, k;
  1029.  
  1030.   // color space
  1031.   if (colorMap) {
  1032.     colorSpace = colorMap->getColorSpace();
  1033.     if (colorSpace->isIndexed())
  1034.       writePS("[/Indexed ");
  1035.     switch (colorSpace->getMode()) {
  1036.     case colorGray:
  1037.       writePS("/DeviceGray ");
  1038.       break;
  1039.     case colorCMYK:
  1040.       writePS("/DeviceCMYK ");
  1041.       break;
  1042.     case colorRGB:
  1043.       writePS("/DeviceRGB ");
  1044.       break;
  1045.     }
  1046.     if (colorSpace->isIndexed()) {
  1047.       n = colorSpace->getIndexHigh();
  1048.       numComps = colorSpace->getNumColorComps();
  1049.       writePS("%d <\n", n);
  1050.       for (i = 0; i <= n; i += 8) {
  1051.     writePS("  ");
  1052.     for (j = i; j < i+8 && j <= n; ++j) {
  1053.       color = colorSpace->getLookupVal(j);
  1054.       for (k = 0; k < numComps; ++k)
  1055.         writePS("%02x", color[k]);
  1056.     }
  1057.     writePS("\n");
  1058.       }
  1059.       writePS("> ] setcolorspace\n");
  1060.     } else {
  1061.       writePS("setcolorspace\n");
  1062.     }
  1063.   }
  1064.  
  1065.   // image dictionary
  1066.   writePS("<<\n  /ImageType 1\n");
  1067.  
  1068.   // width, height, matrix, bits per component
  1069.   writePS("  /Width %d\n", width);
  1070.   writePS("  /Height %d\n", height);
  1071.   writePS("  /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
  1072.   writePS("  /BitsPerComponent %d\n",
  1073.       colorMap ? colorMap->getBits() : 1);
  1074.  
  1075.   // decode 
  1076.   if (colorMap) {
  1077.     writePS("  /Decode [");
  1078.     numComps = colorMap->getNumPixelComps();
  1079.     for (i = 0; i < numComps; ++i) {
  1080.       if (i > 0)
  1081.     writePS(" ");
  1082.       writePS("%g %g", colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
  1083.     }
  1084.     writePS("]\n");
  1085.   } else {
  1086.     writePS("  /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
  1087.   }
  1088.  
  1089.   if (doForm) {
  1090.  
  1091.     // data source
  1092.     writePS("  /DataSource <~\n");
  1093.  
  1094.     // write image data stream, using ASCII85 encode filter
  1095.     str = new ASCII85Encoder(str);
  1096.     str->reset();
  1097.     while ((c = str->getChar()) != EOF)
  1098.       fputc(c, f);
  1099.     fputc('\n', f);
  1100.     delete str;
  1101.  
  1102.     // end of image dictionary
  1103.     writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
  1104.  
  1105.   } else {
  1106.  
  1107.     // data source
  1108.     writePS("  /DataSource currentfile\n");
  1109.     s = str->getPSFilter("    ");
  1110.     if (inlineImg || !s) {
  1111.       useRLE = gTrue;
  1112.       useA85 = gTrue;
  1113.     } else {
  1114.       useRLE = gFalse;
  1115.       useA85 = str->isBinary();
  1116.     }
  1117.     if (useA85)
  1118.       writePS("    /ASCII85Decode filter\n");
  1119.     if (useRLE)
  1120.       writePS("    /RunLengthDecode filter\n");
  1121.     else
  1122.       writePS("%s", s->getCString());
  1123.     if (s)
  1124.       delete s;
  1125.  
  1126.     // end of image dictionary
  1127.     writePS(">>\n%s\n", colorMap ? "pdfIm" : "pdfImM");
  1128.  
  1129.     // write image data stream
  1130.  
  1131.     // cut off inline image streams at appropriate length
  1132.     if (inlineImg)
  1133.       str = new FixedLengthEncoder(str, len);
  1134.     else if (!useRLE)
  1135.       str = str->getBaseStream();
  1136.  
  1137.     // add RunLengthEncode and ASCII85 encode filters
  1138.     if (useRLE)
  1139.       str = new RunLengthEncoder(str);
  1140.     if (useA85)
  1141.       str = new ASCII85Encoder(str);
  1142.  
  1143.     // copy the stream data
  1144.     str->reset();
  1145.     while ((c = str->getChar()) != EOF)
  1146.       fputc(c, f);
  1147.  
  1148.     // add newline and trailer to the end
  1149.     fputc('\n', f);
  1150.     fputs("%-EOD-\n", f);
  1151.  
  1152.     // delete encoders
  1153.     if (useRLE || useA85)
  1154.       delete str;
  1155.   }
  1156. }
  1157.  
  1158. void PSOutputDev::writePS(char *fmt, ...) {
  1159.   va_list args;
  1160.  
  1161.   va_start(args, fmt);
  1162.   vfprintf(f, fmt, args);
  1163.   va_end(args);
  1164. }
  1165.  
  1166. void PSOutputDev::writePSString(GString *s) {
  1167.   Guchar *p;
  1168.   int n;
  1169.  
  1170.   fputc('(', f);
  1171.   for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
  1172.     if (*p == '(' || *p == ')' || *p == '\\')
  1173.       fprintf(f, "\\%c", *p);
  1174.     else if (*p < 0x20 || *p >= 0x80)
  1175.       fprintf(f, "\\%03o", *p);
  1176.     else
  1177.       fputc(*p, f);
  1178.   }
  1179.   fputc(')', f);
  1180. }
  1181.