]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/PSOutputDev.cc
(eog_hig_dialog_new): add terminating NULL in g_object_set.
[evince.git] / pdf / xpdf / PSOutputDev.cc
index 18359119617a158c28ea0a0b0245d0df0aadeac1..7bef193e82db1581ffa804587ab41bc8e0c27941 100644 (file)
@@ -2,21 +2,23 @@
 //
 // PSOutputDev.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
 #pragma implementation
 #endif
 
-#include <aconf.h>
 #include <stdio.h>
 #include <stddef.h>
 #include <stdarg.h>
 #include <signal.h>
 #include <math.h>
 #include "GString.h"
+#include "GList.h"
 #include "config.h"
 #include "GlobalParams.h"
 #include "Object.h"
@@ -54,7 +56,7 @@ static char *prolog[] = {
   "      /PageSize exch def",
   "      /ImagingBBox null def",
   "      /Policies 1 dict dup begin /PageSize 3 def end def",
-  "      /Duplex exch def",
+  "      { /Duplex true def } if",
   "    currentdict end setpagedevice",
   "  } {",
   "    pop pop",
@@ -99,7 +101,7 @@ static char *prolog[] = {
   "  /customcolorimage {",
   "    gsave",
   "    [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
-  "      0 4 getinterval cvx",
+  "      0 4 getinterval",
   "      [ exch /dup load exch { mul exch dup } /forall load",
   "        /pop load dup ] cvx",
   "    ] setcolorspace",
@@ -268,7 +270,8 @@ static char *prolog[] = {
   "      } if",
   "      pdfTextRender 3 and dup 1 eq exch 2 eq or {",
   "        8 6 roll moveto",
-  "        sCol false awcp currentpoint stroke moveto",
+  "        currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
+  "        false awcp currentpoint stroke moveto",
   "      } {",
   "        8 {pop} repeat",
   "      } ifelse",
@@ -326,11 +329,15 @@ static char *prolog[] = {
   "/pdfImSep {",
   "  findcmykcustomcolor exch",
   "  dup /Width get /pdfImBuf1 exch string def",
+  "  dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
+  "  /pdfImDecodeLow exch def",
   "  begin Width Height BitsPerComponent ImageMatrix DataSource end",
   "  /pdfImData exch def",
   "  { pdfImData pdfImBuf1 readstring pop",
   "    0 1 2 index length 1 sub {",
-  "      1 index exch 2 copy get 255 exch sub put",
+  "      1 index exch 2 copy get",
+  "      pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
+  "      255 exch sub put",
   "    } for }",
   "  6 5 roll customcolorimage",
   "  { currentfile pdfImBuf readline",
@@ -488,50 +495,30 @@ extern "C" {
 typedef void (*SignalFunc)(int);
 }
 
+static void outputToFile(void *stream, char *data, int len) {
+  fwrite(data, 1, len, (FILE *)stream);
+}
+
 PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
                         int firstPage, int lastPage, PSOutMode modeA) {
-  Page *page;
-  PDFRectangle *box;
-  Dict *resDict;
-  Annots *annots;
-  char **p;
-  int pg;
-  Object obj1, obj2;
-  int i;
+  FILE *f;
+  PSFileType fileTypeA;
 
-  // initialize
-  xref = xrefA;
-  level = globalParams->getPSLevel();
-  mode = modeA;
-  paperWidth = globalParams->getPSPaperWidth();
-  paperHeight = globalParams->getPSPaperHeight();
   fontIDs = NULL;
   fontFileIDs = NULL;
   fontFileNames = NULL;
   font16Enc = NULL;
+  xobjStack = NULL;
   embFontList = NULL;
-  f = NULL;
-  if (mode == psModeForm) {
-    lastPage = firstPage;
-  }
-  processColors = 0;
   customColors = NULL;
-  inType3Char = gFalse;
   t3String = NULL;
 
-#if OPI_SUPPORT
-  // initialize OPI nesting levels
-  opi13Nest = 0;
-  opi20Nest = 0;
-#endif
-
   // open file or pipe
-  ok = gTrue;
   if (!strcmp(fileName, "-")) {
-    fileType = psStdout;
+    fileTypeA = psStdout;
     f = stdout;
   } else if (fileName[0] == '|') {
-    fileType = psPipe;
+    fileTypeA = psPipe;
 #ifdef HAVE_POPEN
 #ifndef WIN32
     signal(SIGPIPE, (SignalFunc)SIG_IGN);
@@ -547,7 +534,7 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
     return;
 #endif
   } else {
-    fileType = psFile;
+    fileTypeA = psFile;
     if (!(f = fopen(fileName, "w"))) {
       error(-1, "Couldn't open PostScript file '%s'", fileName);
       ok = gFalse;
@@ -555,6 +542,65 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
     }
   }
 
+  init(outputToFile, f, fileTypeA,
+       xrefA, catalog, firstPage, lastPage, modeA);
+}
+
+PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
+                        XRef *xrefA, Catalog *catalog,
+                        int firstPage, int lastPage, PSOutMode modeA) {
+  fontIDs = NULL;
+  fontFileIDs = NULL;
+  fontFileNames = NULL;
+  font16Enc = NULL;
+  xobjStack = NULL;
+  embFontList = NULL;
+  customColors = NULL;
+  t3String = NULL;
+
+  init(outputFuncA, outputStreamA, psGeneric,
+       xrefA, catalog, firstPage, lastPage, modeA);
+}
+
+void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
+                      PSFileType fileTypeA, XRef *xrefA, Catalog *catalog,
+                      int firstPage, int lastPage, PSOutMode modeA) {
+  Page *page;
+  PDFRectangle *box;
+  Dict *resDict;
+  Annots *annots;
+  char **p;
+  int pg;
+  Object obj1, obj2;
+  int i;
+
+  // initialize
+  ok = gTrue;
+  outputFunc = outputFuncA;
+  outputStream = outputStreamA;
+  fileType = fileTypeA;
+  xref = xrefA;
+  level = globalParams->getPSLevel();
+  mode = modeA;
+  paperWidth = globalParams->getPSPaperWidth();
+  paperHeight = globalParams->getPSPaperHeight();
+  if (paperWidth < 0 || paperHeight < 0) {
+    page = catalog->getPage(firstPage);
+    paperWidth = (int)(page->getWidth() + 0.5);
+    paperHeight = (int)(page->getHeight() + 0.5);
+  }
+  if (mode == psModeForm) {
+    lastPage = firstPage;
+  }
+  processColors = 0;
+  inType3Char = gFalse;
+
+#if OPI_SUPPORT
+  // initialize OPI nesting levels
+  opi13Nest = 0;
+  opi20Nest = 0;
+#endif
+
   // initialize fontIDs, fontFileIDs, and fontFileNames lists
   fontIDSize = 64;
   fontIDLen = 0;
@@ -567,6 +613,7 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
   fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
   font16EncLen = 0;
   font16EncSize = 0;
+  xobjStack = new GList();
 
   // initialize embedded font resource comment list
   embFontList = new GString();
@@ -574,66 +621,66 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
   // write header
   switch (mode) {
   case psModePS:
-    writePS("%%!PS-Adobe-3.0\n");
-    writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
-    writePS("%%%%LanguageLevel: %d\n",
-           (level == psLevel1 || level == psLevel1Sep) ? 1 :
-           (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+    writePS("%!PS-Adobe-3.0\n");
+    writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+    writePSFmt("%%%%LanguageLevel: %d\n",
+              (level == psLevel1 || level == psLevel1Sep) ? 1 :
+              (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
     if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
-      writePS("%%%%DocumentProcessColors: (atend)\n");
-      writePS("%%%%DocumentCustomColors: (atend)\n");
-    }
-    writePS("%%%%DocumentSuppliedResources: (atend)\n");
-    writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n",
-           paperWidth, paperHeight);
-    writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
-    writePS("%%%%EndComments\n");
-    writePS("%%%%BeginDefaults\n");
-    writePS("%%%%PageMedia: plain\n");
-    writePS("%%%%EndDefaults\n");
+      writePS("%%DocumentProcessColors: (atend)\n");
+      writePS("%%DocumentCustomColors: (atend)\n");
+    }
+    writePS("%%DocumentSuppliedResources: (atend)\n");
+    writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
+              paperWidth, paperHeight);
+    writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1);
+    writePS("%%EndComments\n");
+    writePS("%%BeginDefaults\n");
+    writePS("%%PageMedia: plain\n");
+    writePS("%%EndDefaults\n");
     break;
   case psModeEPS:
-    writePS("%%!PS-Adobe-3.0 EPSF-3.0\n");
-    writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
-    writePS("%%%%LanguageLevel: %d\n",
-           (level == psLevel1 || level == psLevel1Sep) ? 1 :
-           (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+    writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
+    writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+    writePSFmt("%%%%LanguageLevel: %d\n",
+              (level == psLevel1 || level == psLevel1Sep) ? 1 :
+              (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
     if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
-      writePS("%%%%DocumentProcessColors: (atend)\n");
-      writePS("%%%%DocumentCustomColors: (atend)\n");
+      writePS("%%DocumentProcessColors: (atend)\n");
+      writePS("%%DocumentCustomColors: (atend)\n");
     }
     page = catalog->getPage(firstPage);
     box = page->getBox();
-    writePS("%%%%BoundingBox: %d %d %d %d\n",
-           (int)floor(box->x1), (int)floor(box->y1),
-           (int)ceil(box->x2), (int)ceil(box->y2));
+    writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
+              (int)floor(box->x1), (int)floor(box->y1),
+              (int)ceil(box->x2), (int)ceil(box->y2));
     if (floor(box->x1) != ceil(box->x1) ||
        floor(box->y1) != ceil(box->y1) ||
        floor(box->x2) != ceil(box->x2) ||
        floor(box->y2) != ceil(box->y2)) {
-      writePS("%%%%HiResBoundingBox: %g %g %g %g\n",
-             box->x1, box->y1, box->x2, box->y2);
+      writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n",
+                box->x1, box->y1, box->x2, box->y2);
     }
-    writePS("%%%%DocumentSuppliedResources: (atend)\n");
-    writePS("%%%%EndComments\n");
+    writePS("%%DocumentSuppliedResources: (atend)\n");
+    writePS("%%EndComments\n");
     break;
   case psModeForm:
-    writePS("%%!PS-Adobe-3.0 Resource-Form\n");
-    writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
-    writePS("%%%%LanguageLevel: %d\n",
-           (level == psLevel1 || level == psLevel1Sep) ? 1 :
-           (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+    writePS("%!PS-Adobe-3.0 Resource-Form\n");
+    writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+    writePSFmt("%%%%LanguageLevel: %d\n",
+              (level == psLevel1 || level == psLevel1Sep) ? 1 :
+              (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
     if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
-      writePS("%%%%DocumentProcessColors: (atend)\n");
-      writePS("%%%%DocumentCustomColors: (atend)\n");
+      writePS("%%DocumentProcessColors: (atend)\n");
+      writePS("%%DocumentCustomColors: (atend)\n");
     }
-    writePS("%%%%DocumentSuppliedResources: (atend)\n");
-    writePS("%%%%EndComments\n");
+    writePS("%%DocumentSuppliedResources: (atend)\n");
+    writePS("%%EndComments\n");
     page = catalog->getPage(firstPage);
     box = page->getBox();
     writePS("32 dict dup begin\n");
-    writePS("/BBox [%d %d %d %d] def\n",
-           (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2);
+    writePSFmt("/BBox [%d %d %d %d] def\n",
+              (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2);
     writePS("/FormType 1 def\n");
     writePS("/Matrix [1 0 0 1 0 0] def\n");
     break;
@@ -641,20 +688,20 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
 
   // write prolog
   if (mode != psModeForm) {
-    writePS("%%%%BeginProlog\n");
+    writePS("%%BeginProlog\n");
   }
-  writePS("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
+  writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
   for (p = prolog; *p; ++p) {
-    writePS("%s\n", *p);
+    writePSFmt("%s\n", *p);
   }
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
   if (level >= psLevel3) {
     for (p = cmapProlog; *p; ++p) {
-      writePS("%s\n", *p);
+      writePSFmt("%s\n", *p);
     }
   }
   if (mode != psModeForm) {
-    writePS("%%%%EndProlog\n");
+    writePS("%%EndProlog\n");
   }
 
   // set up fonts and images
@@ -662,7 +709,7 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
     // swap the form and xpdf dicts
     writePS("xpdf end begin dup begin\n");
   } else {
-    writePS("%%%%BeginSetup\n");
+    writePS("%%BeginSetup\n");
     writePS("xpdf begin\n");
   }
   for (pg = firstPage; pg <= lastPage; ++pg) {
@@ -686,16 +733,16 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
   }
   if (mode != psModeForm) {
     if (mode != psModeEPS) {
-      writePS("%d %d %s pdfSetup\n",
-             paperWidth, paperHeight,
-             globalParams->getPSDuplex() ? "true" : "false");
+      writePSFmt("%d %d %s pdfSetup\n",
+                paperWidth, paperHeight,
+                globalParams->getPSDuplex() ? "true" : "false");
     }
 #if OPI_SUPPORT
     if (globalParams->getPSOPI()) {
       writePS("/opiMatrix matrix currentmatrix def\n");
     }
 #endif
-    writePS("%%%%EndSetup\n");
+    writePS("%%EndSetup\n");
   }
 
   // initialize sequential page number
@@ -706,17 +753,17 @@ PSOutputDev::~PSOutputDev() {
   PSOutCustomColor *cc;
   int i;
 
-  if (f) {
+  if (ok) {
     if (mode == psModeForm) {
       writePS("/Foo exch /Form defineresource pop\n");
     } else {
-      writePS("%%%%Trailer\n");
+      writePS("%%Trailer\n");
       writePS("end\n");
-      writePS("%%%%DocumentSuppliedResources:\n");
-      writePS("%s", embFontList->getCString());
+      writePS("%%DocumentSuppliedResources:\n");
+      writePS(embFontList->getCString());
       if (level == psLevel1Sep || level == psLevel2Sep ||
          level == psLevel3Sep) {
-         writePS("%%%%DocumentProcessColors:");
+         writePS("%%DocumentProcessColors:");
          if (processColors & psProcessCyan) {
           writePS(" Cyan");
         }
@@ -730,28 +777,28 @@ PSOutputDev::~PSOutputDev() {
           writePS(" Black");
         }
          writePS("\n");
-         writePS("%%%%DocumentCustomColors:");
+         writePS("%%DocumentCustomColors:");
         for (cc = customColors; cc; cc = cc->next) {
-          writePS(" (%s)", cc->name->getCString());
+          writePSFmt(" (%s)", cc->name->getCString());
         }
          writePS("\n");
-         writePS("%%%%CMYKCustomColor:\n");
+         writePS("%%CMYKCustomColor:\n");
         for (cc = customColors; cc; cc = cc->next) {
-          writePS("%%%%+ %g %g %g %g (%s)\n",
+          writePSFmt("%%%%+ %g %g %g %g (%s)\n",
                   cc->c, cc->m, cc->y, cc->k, cc->name->getCString());
         }
       }
-      writePS("%%%%EOF\n");
+      writePS("%%EOF\n");
     }
     if (fileType == psFile) {
 #ifdef MACOS
-      ICS_MapRefNumAndAssign((short)f->handle);
+      ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
 #endif
-      fclose(f);
+      fclose((FILE *)outputStream);
     }
 #ifdef HAVE_POPEN
     else if (fileType == psPipe) {
-      pclose(f);
+      pclose((FILE *)outputStream);
 #ifndef WIN32
       signal(SIGPIPE, (SignalFunc)SIG_DFL);
 #endif
@@ -779,6 +826,9 @@ PSOutputDev::~PSOutputDev() {
     }
     gfree(font16Enc);
   }
+  if (xobjStack) {
+    delete xobjStack;
+  }
   while (customColors) {
     cc = customColors;
     customColors = cc->next;
@@ -787,8 +837,10 @@ PSOutputDev::~PSOutputDev() {
 }
 
 void PSOutputDev::setupResources(Dict *resDict) {
-  Object xObjDict, xObj, resObj;
-  int i;
+  Object xObjDict, xObjRef, xObj, resObj;
+  Ref ref0, ref1;
+  GBool skip;
+  int i, j;
 
   setupFonts(resDict);
   setupImages(resDict);
@@ -796,15 +848,40 @@ void PSOutputDev::setupResources(Dict *resDict) {
   resDict->lookup("XObject", &xObjDict);
   if (xObjDict.isDict()) {
     for (i = 0; i < xObjDict.dictGetLength(); ++i) {
-      xObjDict.dictGetVal(i, &xObj);
-      if (xObj.isStream()) {
-       xObj.streamGetDict()->lookup("Resources", &resObj);
-       if (resObj.isDict()) {
-         setupResources(resObj.getDict());
+
+      // avoid infinite recursion on XObjects
+      skip = gFalse;
+      if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
+       ref0 = xObjRef.getRef();
+       for (j = 0; j < xobjStack->getLength(); ++j) {
+         ref1 = *(Ref *)xobjStack->get(j);
+         if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
+           skip = gTrue;
+           break;
+         }
+       }
+       if (!skip) {
+         xobjStack->append(&ref0);
        }
-       resObj.free();
       }
-      xObj.free();
+      if (!skip) {
+
+       // process the XObject's resource dictionary
+       xObjDict.dictGetVal(i, &xObj);
+       if (xObj.isStream()) {
+         xObj.streamGetDict()->lookup("Resources", &resObj);
+         if (resObj.isDict()) {
+           setupResources(resObj.getDict());
+         }
+         resObj.free();
+       }
+       xObj.free();
+      }
+
+      if (xObjRef.isRef() && !skip) {
+       xobjStack->del(xobjStack->getLength() - 1);
+      }
+      xObjRef.free();
     }
   }
   xObjDict.free();
@@ -834,7 +911,8 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
   PSFontParam *fontParam;
   GString *psNameStr;
   char *psName;
-  char type3Name[64];
+  char type3Name[64], buf[16];
+  GBool subst;
   UnicodeMap *uMap;
   char *charName;
   double xs, ys;
@@ -860,6 +938,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
 
   xs = ys = 1;
   psNameStr = NULL;
+  subst = gFalse;
 
   // check for resident 8-bit font
   if (font->getName() &&
@@ -930,6 +1009,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
 
   // do 8-bit font substitution
   } else if (!font->isCIDFont()) {
+    subst = gTrue;
     name = font->getName();
     psName = NULL;
     if (name) {
@@ -991,6 +1071,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
                getPSFont16(font->getName(),
                            ((GfxCIDFont *)font)->getCollection(),
                            font->getWMode()))) {
+    subst = gTrue;
     psName = fontParam->psFontName->getCString();
     if (font16EncLen >= font16EncSize) {
       font16EncSize += 16;
@@ -1020,29 +1101,37 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
   // generate PostScript code to set up the font
   if (font->isCIDFont()) {
     if (level == psLevel3 || level == psLevel3Sep) {
-      writePS("/F%d_%d /%s %d pdfMakeFont16L3\n",
-             font->getID()->num, font->getID()->gen, psName,
-             font->getWMode());
+      writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
+                font->getID()->num, font->getID()->gen, psName,
+                font->getWMode());
     } else {
-      writePS("/F%d_%d /%s %d pdfMakeFont16\n",
-             font->getID()->num, font->getID()->gen, psName,
-             font->getWMode());
+      writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
+                font->getID()->num, font->getID()->gen, psName,
+                font->getWMode());
     }
   } else {
-    writePS("/F%d_%d /%s %g %g\n",
-           font->getID()->num, font->getID()->gen, psName, xs, ys);
+    writePSFmt("/F%d_%d /%s %g %g\n",
+              font->getID()->num, font->getID()->gen, psName, xs, ys);
     for (i = 0; i < 256; i += 8) {
-      writePS((i == 0) ? "[ " : "  ");
+      writePSFmt((i == 0) ? "[ " : "  ");
       for (j = 0; j < 8; ++j) {
-       charName = ((Gfx8BitFont *)font)->getCharName(i+j);
-       // this is a kludge for broken PDF files that encode char 32
-       // as .notdef
-       if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
-         charName = "space";
+       if (font->getType() == fontTrueType &&
+           !subst &&
+           !((Gfx8BitFont *)font)->getHasEncoding()) {
+         sprintf(buf, "c%02x", i+j);
+         charName = buf;
+       } else {
+         charName = ((Gfx8BitFont *)font)->getCharName(i+j);
+         // this is a kludge for broken PDF files that encode char 32
+         // as .notdef
+         if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
+           charName = "space";
+         }
        }
-       writePS("/%s", charName ? charName : ".notdef");
+       writePS("/");
+       writePSName(charName ? charName : (char *)".notdef");
       }
-      writePS((i == 256-8) ? "]\n" : "\n");
+      writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
     }
     writePS("pdfMakeFont\n");
   }
@@ -1102,7 +1191,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
   obj2.free();
 
   // beginning comment
-  writePS("%%%%BeginResource: font %s\n", psName);
+  writePSFmt("%%%%BeginResource: font %s\n", psName);
   embFontList->append("%%+ font ");
   embFontList->append(psName);
   embFontList->append("\n");
@@ -1168,7 +1257,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
   writePS("cleartomark\n");
 
   // ending comment
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
 
  err1:
   strObj.streamClose();
@@ -1198,7 +1287,7 @@ void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) {
   fontFileNames[fontFileNameLen++] = fileName->copy();
 
   // beginning comment
-  writePS("%%%%BeginResource: font %s\n", psName);
+  writePSFmt("%%%%BeginResource: font %s\n", psName);
   embFontList->append("%%+ font ");
   embFontList->append(psName);
   embFontList->append("\n");
@@ -1214,7 +1303,7 @@ void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) {
   fclose(fontFile);
 
   // ending comment
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
 }
 
 void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
@@ -1239,7 +1328,7 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
   fontFileIDs[fontFileIDLen++] = *id;
 
   // beginning comment
-  writePS("%%%%BeginResource: font %s\n", psName);
+  writePSFmt("%%%%BeginResource: font %s\n", psName);
   embFontList->append("%%+ font ");
   embFontList->append(psName);
   embFontList->append("\n");
@@ -1247,12 +1336,14 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
   // convert it to a Type 1 font
   fontBuf = font->readEmbFontFile(xref, &fontLen);
   t1cFile = new Type1CFontFile(fontBuf, fontLen);
-  t1cFile->convertToType1(f);
+  if (t1cFile->isOk()) {
+    t1cFile->convertToType1(outputFunc, outputStream);
+  }
   delete t1cFile;
   gfree(fontBuf);
 
   // ending comment
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
 }
 
 void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
@@ -1278,7 +1369,7 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
   fontFileIDs[fontFileIDLen++] = *id;
 
   // beginning comment
-  writePS("%%%%BeginResource: font %s\n", psName);
+  writePSFmt("%%%%BeginResource: font %s\n", psName);
   embFontList->append("%%+ font ");
   embFontList->append(psName);
   embFontList->append("\n");
@@ -1288,13 +1379,15 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
   ttFile = new TrueTypeFontFile(fontBuf, fontLen);
   ctu = ((Gfx8BitFont *)font)->getToUnicode();
   ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
-                         ctu, ((Gfx8BitFont *)font)->getHasEncoding(), f);
+                         ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
+                         ((Gfx8BitFont *)font)->isSymbolic(),
+                         outputFunc, outputStream);
   ctu->decRefCnt();
   delete ttFile;
   gfree(fontBuf);
 
   // ending comment
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
 }
 
 void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) {
@@ -1322,7 +1415,7 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) {
   fontFileNames[fontFileNameLen++] = fileName->copy();
 
   // beginning comment
-  writePS("%%%%BeginResource: font %s\n", psName);
+  writePSFmt("%%%%BeginResource: font %s\n", psName);
   embFontList->append("%%+ font ");
   embFontList->append(psName);
   embFontList->append("\n");
@@ -1332,13 +1425,15 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) {
   ttFile = new TrueTypeFontFile(fontBuf, fontLen);
   ctu = ((Gfx8BitFont *)font)->getToUnicode();
   ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
-                         ctu, ((Gfx8BitFont *)font)->getHasEncoding(), f);
+                         ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
+                         ((Gfx8BitFont *)font)->isSymbolic(),
+                         outputFunc, outputStream);
   ctu->decRefCnt();
   delete ttFile;
   gfree(fontBuf);
 
   // ending comment
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
 }
 
 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
@@ -1363,7 +1458,7 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
   fontFileIDs[fontFileIDLen++] = *id;
 
   // beginning comment
-  writePS("%%%%BeginResource: font %s\n", psName);
+  writePSFmt("%%%%BeginResource: font %s\n", psName);
   embFontList->append("%%+ font ");
   embFontList->append(psName);
   embFontList->append("\n");
@@ -1371,18 +1466,20 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
   // convert it to a Type 0 font
   fontBuf = font->readEmbFontFile(xref, &fontLen);
   t1cFile = new Type1CFontFile(fontBuf, fontLen);
-  if (globalParams->getPSLevel() >= psLevel3) {
-    // Level 3: use a CID font
-    t1cFile->convertToCIDType0(psName, f);
-  } else {
-    // otherwise: use a non-CID composite font
-    t1cFile->convertToType0(psName, f);
+  if (t1cFile->isOk()) {
+    if (globalParams->getPSLevel() >= psLevel3) {
+      // Level 3: use a CID font
+      t1cFile->convertToCIDType0(psName, outputFunc, outputStream);
+    } else {
+      // otherwise: use a non-CID composite font
+      t1cFile->convertToType0(psName, outputFunc, outputStream);
+    }
   }
   delete t1cFile;
   gfree(fontBuf);
 
   // ending comment
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
 }
 
 void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
@@ -1407,7 +1504,7 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
   fontFileIDs[fontFileIDLen++] = *id;
 
   // beginning comment
-  writePS("%%%%BeginResource: font %s\n", psName);
+  writePSFmt("%%%%BeginResource: font %s\n", psName);
   embFontList->append("%%+ font ");
   embFontList->append(psName);
   embFontList->append("\n");
@@ -1418,17 +1515,19 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
   if (globalParams->getPSLevel() >= psLevel3) {
     ttFile->convertToCIDType2(psName,
                              ((GfxCIDFont *)font)->getCIDToGID(),
-                             ((GfxCIDFont *)font)->getCIDToGIDLen(), f);
+                             ((GfxCIDFont *)font)->getCIDToGIDLen(),
+                             outputFunc, outputStream);
   } else {
     // otherwise: use a non-CID composite font
     ttFile->convertToType0(psName, ((GfxCIDFont *)font)->getCIDToGID(),
-                          ((GfxCIDFont *)font)->getCIDToGIDLen(), f);
+                          ((GfxCIDFont *)font)->getCIDToGIDLen(),
+                          outputFunc, outputStream);
   }
   delete ttFile;
   gfree(fontBuf);
 
   // ending comment
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
 }
 
 void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
@@ -1439,6 +1538,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
   Gfx *gfx;
   PDFRectangle box;
   double *m;
+  char buf[256];
   int i;
 
   // set up resources used by font
@@ -1449,7 +1549,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
   }
 
   // beginning comment
-  writePS("%%%%BeginResource: font %s\n", psName);
+  writePSFmt("%%%%BeginResource: font %s\n", psName);
   embFontList->append("%%+ font ");
   embFontList->append(psName);
   embFontList->append("\n");
@@ -1458,11 +1558,11 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
   writePS("7 dict begin\n");
   writePS("/FontType 3 def\n");
   m = font->getFontMatrix();
-  writePS("/FontMatrix [%g %g %g %g %g %g] def\n",
-         m[0], m[1], m[2], m[3], m[4], m[5]);
+  writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n",
+            m[0], m[1], m[2], m[3], m[4], m[5]);
   m = font->getFontBBox();
-  writePS("/FontBBox [%g %g %g %g] def\n",
-         m[0], m[1], m[2], m[3]);
+  writePSFmt("/FontBBox [%g %g %g %g] def\n",
+            m[0], m[1], m[2], m[3]);
   writePS("/Encoding 256 array def\n");
   writePS("  0 1 255 { Encoding exch /.notdef put } for\n");
   writePS("/BuildGlyph {\n");
@@ -1475,7 +1575,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
   writePS("  1 index /BuildGlyph get exec\n");
   writePS("} bind def\n");
   if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
-    writePS("/CharProcs %d dict def\n", charProcs->getLength());
+    writePSFmt("/CharProcs %d dict def\n", charProcs->getLength());
     writePS("CharProcs begin\n");
     box.x1 = m[0];
     box.y1 = m[1];
@@ -1483,22 +1583,27 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
     box.y2 = m[3];
     gfx = new Gfx(xref, this, resDict, &box, gFalse, NULL);
     inType3Char = gTrue;
+    t3Cacheable = gFalse;
     for (i = 0; i < charProcs->getLength(); ++i) {
-      writePS("/%s {\n", charProcs->getKey(i));
+      writePS("/");
+      writePSName(charProcs->getKey(i));
+      writePS(" {\n");
       gfx->display(charProcs->getVal(i, &charProc));
       charProc.free();
       if (t3String) {
        if (t3Cacheable) {
-         fprintf(f, "%g %g %g %g %g %g setcachedevice\n",
+         sprintf(buf, "%g %g %g %g %g %g setcachedevice\n",
                  t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
        } else {
-         fprintf(f, "%g %g setcharwidth\n", t3WX, t3WY);
+         sprintf(buf, "%g %g setcharwidth\n", t3WX, t3WY);
        }
-       fputs(t3String->getCString(), f);
+       (*outputFunc)(outputStream, buf, strlen(buf));
+       (*outputFunc)(outputStream, t3String->getCString(),
+                     t3String->getLength());
        delete t3String;
        t3String = NULL;
       }
-      fputs("Q\n", f);
+      (*outputFunc)(outputStream, "Q\n", 2);
       writePS("} def\n");
     }
     inType3Char = gFalse;
@@ -1506,10 +1611,10 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
     writePS("end\n");
   }
   writePS("currentdict end\n");
-  writePS("/%s exch definefont pop\n", psName);
+  writePSFmt("/%s exch definefont pop\n", psName);
 
   // ending comment
-  writePS("%%%%EndResource\n");
+  writePS("%%EndResource\n");
 }
 
 void PSOutputDev::setupImages(Dict *resDict) {
@@ -1584,7 +1689,7 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
     }
   } while (c != '~' && c != EOF);
   ++size;
-  writePS("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
+  writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
 
   // write the data into the array
   str->reset();
@@ -1621,7 +1726,7 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
     if (col > 225) {
       writePS("~> put\n");
       ++line;
-      writePS("dup %d <~", line);
+      writePSFmt("dup %d <~", line);
       col = 0;
     }
   } while (c != '~' && c != EOF);
@@ -1634,11 +1739,12 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
 void PSOutputDev::startPage(int pageNum, GfxState *state) {
   int x1, y1, x2, y2, width, height, t;
 
+
   switch (mode) {
 
   case psModePS:
-    writePS("%%%%Page: %d %d\n", pageNum, seqPage);
-    writePS("%%%%BeginPageSetup\n");
+    writePSFmt("%%%%Page: %d %d\n", pageNum, seqPage);
+    writePS("%%BeginPageSetup\n");
 
     // rotate, translate, and scale page
     x1 = (int)(state->getX1() + 0.5);
@@ -1649,8 +1755,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
     height = y2 - y1;
     if (width > height && width > paperWidth) {
       landscape = gTrue;
-      writePS("%%%%PageOrientation: %s\n",
-             state->getCTM()[0] ? "Landscape" : "Portrait");
+      writePSFmt("%%%%PageOrientation: %s\n",
+                state->getCTM()[0] ? "Landscape" : "Portrait");
       writePS("pdfStartPage\n");
       writePS("90 rotate\n");
       tx = -x1;
@@ -1660,8 +1766,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
       height = t;
     } else {
       landscape = gFalse;
-      writePS("%%%%PageOrientation: %s\n",
-             state->getCTM()[0] ? "Portrait" : "Landscape");
+      writePSFmt("%%%%PageOrientation: %s\n",
+                state->getCTM()[0] ? "Portrait" : "Landscape");
       writePS("pdfStartPage\n");
       tx = -x1;
       ty = -y1;
@@ -1673,7 +1779,7 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
       ty += (paperHeight - height) / 2;
     }
     if (tx != 0 || ty != 0) {
-      writePS("%g %g translate\n", tx, ty);
+      writePSFmt("%g %g translate\n", tx, ty);
     }
     if (width > paperWidth || height > paperHeight) {
       xScale = (double)paperWidth / (double)width;
@@ -1683,12 +1789,12 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
       } else {
        yScale = xScale;
       }
-      writePS("%0.4f %0.4f scale\n", xScale, xScale);
+      writePSFmt("%0.4f %0.4f scale\n", xScale, xScale);
     } else {
       xScale = yScale = 1;
     }
 
-    writePS("%%%%EndPageSetup\n");
+    writePS("%%EndPageSetup\n");
     ++seqPage;
     break;
 
@@ -1711,6 +1817,7 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
 }
 
 void PSOutputDev::endPage() {
+
   if (mode == psModeForm) {
     writePS("pdfEndPage\n");
     writePS("end end\n");
@@ -1718,7 +1825,7 @@ void PSOutputDev::endPage() {
     writePS("end end\n");
   } else {
     writePS("showpage\n");
-    writePS("%%%%PageTrailer\n");
+    writePS("%%PageTrailer\n");
     writePS("pdfEndPage\n");
   }
 }
@@ -1733,7 +1840,7 @@ void PSOutputDev::restoreState(GfxState *state) {
 
 void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
                            double m21, double m22, double m31, double m32) {
-  writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
+  writePSFmt("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
 }
 
 void PSOutputDev::updateLineDash(GfxState *state) {
@@ -1744,28 +1851,28 @@ void PSOutputDev::updateLineDash(GfxState *state) {
   state->getLineDash(&dash, &length, &start);
   writePS("[");
   for (i = 0; i < length; ++i)
-    writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
-  writePS("] %g d\n", start);
+    writePSFmt("%g%s", dash[i], (i == length-1) ? "" : " ");
+  writePSFmt("] %g d\n", start);
 }
 
 void PSOutputDev::updateFlatness(GfxState *state) {
-  writePS("%d i\n", state->getFlatness());
+  writePSFmt("%d i\n", state->getFlatness());
 }
 
 void PSOutputDev::updateLineJoin(GfxState *state) {
-  writePS("%d j\n", state->getLineJoin());
+  writePSFmt("%d j\n", state->getLineJoin());
 }
 
 void PSOutputDev::updateLineCap(GfxState *state) {
-  writePS("%d J\n", state->getLineCap());
+  writePSFmt("%d J\n", state->getLineCap());
 }
 
 void PSOutputDev::updateMiterLimit(GfxState *state) {
-  writePS("%g M\n", state->getMiterLimit());
+  writePSFmt("%g M\n", state->getMiterLimit());
 }
 
 void PSOutputDev::updateLineWidth(GfxState *state) {
-  writePS("%g w\n", state->getLineWidth());
+  writePSFmt("%g w\n", state->getLineWidth());
 }
 
 void PSOutputDev::updateFillColor(GfxState *state) {
@@ -1778,23 +1885,24 @@ void PSOutputDev::updateFillColor(GfxState *state) {
   switch (level) {
   case psLevel1:
     state->getFillGray(&gray);
-    writePS("%g g\n", gray);
+    writePSFmt("%g g\n", gray);
     break;
   case psLevel1Sep:
     state->getFillCMYK(&cmyk);
-    writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+    writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+    addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
     break;
   case psLevel2:
   case psLevel3:
     if (state->getFillColorSpace()->getMode() == csDeviceCMYK) {
       state->getFillCMYK(&cmyk);
-      writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+      writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
     } else {
       state->getFillRGB(&rgb);
       if (rgb.r == rgb.g && rgb.g == rgb.b) {
-       writePS("%g g\n", rgb.r);
+       writePSFmt("%g g\n", rgb.r);
       } else {
-       writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
+       writePSFmt("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
       }
     }
     break;
@@ -1804,14 +1912,14 @@ void PSOutputDev::updateFillColor(GfxState *state) {
       sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
       color.c[0] = 1;
       sepCS->getCMYK(&color, &cmyk);
-      writePS("%g %g %g %g %g (%s) ck\n",
-             state->getFillColor()->c[0],
-             cmyk.c, cmyk.m, cmyk.y, cmyk.k,
-             sepCS->getName()->getCString());
+      writePSFmt("%g %g %g %g %g (%s) ck\n",
+                state->getFillColor()->c[0],
+                cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+                sepCS->getName()->getCString());
       addCustomColor(sepCS);
     } else {
       state->getFillCMYK(&cmyk);
-      writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+      writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
       addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
     }
     break;
@@ -1829,23 +1937,24 @@ void PSOutputDev::updateStrokeColor(GfxState *state) {
   switch (level) {
   case psLevel1:
     state->getStrokeGray(&gray);
-    writePS("%g G\n", gray);
+    writePSFmt("%g G\n", gray);
     break;
   case psLevel1Sep:
     state->getStrokeCMYK(&cmyk);
-    writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+    writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+    addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
     break;
   case psLevel2:
   case psLevel3:
     if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) {
       state->getStrokeCMYK(&cmyk);
-      writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+      writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
     } else {
       state->getStrokeRGB(&rgb);
       if (rgb.r == rgb.g && rgb.g == rgb.b) {
-       writePS("%g G\n", rgb.r);
+       writePSFmt("%g G\n", rgb.r);
       } else {
-       writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
+       writePSFmt("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
       }
     }
     break;
@@ -1855,14 +1964,14 @@ void PSOutputDev::updateStrokeColor(GfxState *state) {
       sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
       color.c[0] = 1;
       sepCS->getCMYK(&color, &cmyk);
-      writePS("%g %g %g %g %g (%s) CK\n",
-             state->getStrokeColor()->c[0],
-             cmyk.c, cmyk.m, cmyk.y, cmyk.k,
-             sepCS->getName()->getCString());
+      writePSFmt("%g %g %g %g %g (%s) CK\n",
+                state->getStrokeColor()->c[0],
+                cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+                sepCS->getName()->getCString());
       addCustomColor(sepCS);
     } else {
       state->getStrokeCMYK(&cmyk);
-      writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+      writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
       addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
     }
     break;
@@ -1905,9 +2014,9 @@ void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
 
 void PSOutputDev::updateFont(GfxState *state) {
   if (state->getFont()) {
-    writePS("/F%d_%d %g Tf\n",
-           state->getFont()->getID()->num, state->getFont()->getID()->gen,
-           state->getFontSize());
+    writePSFmt("/F%d_%d %g Tf\n",
+              state->getFont()->getID()->num, state->getFont()->getID()->gen,
+              state->getFontSize());
   }
 }
 
@@ -1915,19 +2024,19 @@ void PSOutputDev::updateTextMat(GfxState *state) {
   double *mat;
 
   mat = state->getTextMat();
-  writePS("[%g %g %g %g %g %g] Tm\n",
-         mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+  writePSFmt("[%g %g %g %g %g %g] Tm\n",
+            mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
 }
 
 void PSOutputDev::updateCharSpace(GfxState *state) {
-  writePS("%g Tc\n", state->getCharSpace());
+  writePSFmt("%g Tc\n", state->getCharSpace());
 }
 
 void PSOutputDev::updateRender(GfxState *state) {
   int rm;
 
   rm = state->getRender();
-  writePS("%d Tr\n", rm);
+  writePSFmt("%d Tr\n", rm);
   rm &= 3;
   if (rm != 0 && rm != 3) {
     t3Cacheable = gFalse;
@@ -1935,26 +2044,26 @@ void PSOutputDev::updateRender(GfxState *state) {
 }
 
 void PSOutputDev::updateRise(GfxState *state) {
-  writePS("%g Ts\n", state->getRise());
+  writePSFmt("%g Ts\n", state->getRise());
 }
 
 void PSOutputDev::updateWordSpace(GfxState *state) {
-  writePS("%g Tw\n", state->getWordSpace());
+  writePSFmt("%g Tw\n", state->getWordSpace());
 }
 
 void PSOutputDev::updateHorizScaling(GfxState *state) {
-  writePS("%g Tz\n", state->getHorizScaling());
+  writePSFmt("%g Tz\n", state->getHorizScaling());
 }
 
 void PSOutputDev::updateTextPos(GfxState *state) {
-  writePS("%g %g Td\n", state->getLineX(), state->getLineY());
+  writePSFmt("%g %g Td\n", state->getLineX(), state->getLineY());
 }
 
 void PSOutputDev::updateTextShift(GfxState *state, double shift) {
   if (state->getFont()->getWMode()) {
-    writePS("%g TJmV\n", shift);
+    writePSFmt("%g TJmV\n", shift);
   } else {
-    writePS("%g TJm\n", shift);
+    writePSFmt("%g TJm\n", shift);
   }
 }
 
@@ -2010,14 +2119,14 @@ void PSOutputDev::doPath(GfxPath *path) {
       x3 = subpath->getX(3);
       y3 = subpath->getY(3);
       if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
-       writePS("%g %g %g %g re\n",
-               x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
-               fabs(x2 - x0), fabs(y1 - y0));
+       writePSFmt("%g %g %g %g re\n",
+                  x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
+                  fabs(x2 - x0), fabs(y1 - y0));
        return;
       } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
-       writePS("%g %g %g %g re\n",
-               x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
-               fabs(x1 - x0), fabs(y2 - y0));
+       writePSFmt("%g %g %g %g re\n",
+                  x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
+                  fabs(x1 - x0), fabs(y2 - y0));
        return;
       }
     }
@@ -2026,16 +2135,16 @@ void PSOutputDev::doPath(GfxPath *path) {
   for (i = 0; i < n; ++i) {
     subpath = path->getSubpath(i);
     m = subpath->getNumPoints();
-    writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
+    writePSFmt("%g %g m\n", subpath->getX(0), subpath->getY(0));
     j = 1;
     while (j < m) {
       if (subpath->getCurve(j)) {
-       writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
-               subpath->getX(j+1), subpath->getY(j+1),
-               subpath->getX(j+2), subpath->getY(j+2));
+       writePSFmt("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
+                  subpath->getX(j+1), subpath->getY(j+1),
+                  subpath->getX(j+2), subpath->getY(j+2));
        j += 3;
       } else {
-       writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
+       writePSFmt("%g %g l\n", subpath->getX(j), subpath->getY(j));
        ++j;
       }
     }
@@ -2134,12 +2243,12 @@ void PSOutputDev::drawString(GfxState *state, GString *s) {
     writePSString(s2);
     if (font->isCIDFont()) {
       if (wMode) {
-       writePS(" %d %g Tj16V\n", nChars, dy);
+       writePSFmt(" %d %g Tj16V\n", nChars, dy);
       } else {
-       writePS(" %d %g Tj16\n", nChars, dx);
+       writePSFmt(" %d %g Tj16\n", nChars, dx);
       }
     } else {
-      writePS(" %g Tj\n", dx);
+      writePSFmt(" %g Tj\n", dx);
     }
   }
   if (font->isCIDFont()) {
@@ -2195,13 +2304,13 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
 
   // width, height, matrix, bits per component
   if (colorMap) {
-    writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
-           width, height,
-           width, -height, height);
+    writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
+              width, height,
+              width, -height, height);
   } else {
-    writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
-           width, height, invert ? "true" : "false",
-           width, -height, height);
+    writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
+              width, height, invert ? "true" : "false",
+              width, -height, height);
   }
 
   // image
@@ -2220,7 +2329,7 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
       for (x = 0; x < width; ++x) {
        imgStr->getPixel(pixBuf);
        colorMap->getGray(pixBuf, &gray);
-       writePS("%02x", (int)(gray * 255 + 0.5));
+       writePSFmt("%02x", (int)(gray * 255 + 0.5));
        if (++i == 32) {
          writePSChar('\n');
          i = 0;
@@ -2238,7 +2347,7 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
     i = 0;
     for (y = 0; y < height; ++y) {
       for (x = 0; x < width; x += 8) {
-       writePS("%02x", str->getChar() & 0xff);
+       writePSFmt("%02x", str->getChar() & 0xff);
        if (++i == 32) {
          writePSChar('\n');
          i = 0;
@@ -2262,9 +2371,9 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
   int x, y, i, comp;
 
   // width, height, matrix, bits per component
-  writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
-           width, height,
-           width, -height, height);
+  writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
+            width, height,
+            width, -height, height);
 
   // allocate a line buffer
   lineBuf = (Guchar *)gmalloc(4 * width);
@@ -2286,12 +2395,13 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
       lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5);
       lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5);
       lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5);
+      addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
     }
 
     // write one line of each color component
     for (comp = 0; comp < 4; ++comp) {
       for (x = 0; x < width; ++x) {
-       writePS("%02x", lineBuf[4*x + comp]);
+       writePSFmt("%02x", lineBuf[4*x + comp]);
        if (++i == 32) {
          writePSChar('\n');
          i = 0;
@@ -2318,7 +2428,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
   GfxColor color;
   GfxCMYK cmyk;
   int c;
-  int i;
+  int line, col, i;
 
   // color space
   if (colorMap) {
@@ -2326,20 +2436,72 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
     writePS(" setcolorspace\n");
   }
 
-  // set up to use the array created by setupImages()
-  if ((mode == psModeForm || inType3Char) && !inlineImg) {
-    writePS("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
+  // set up the image data
+  if (mode == psModeForm || inType3Char) {
+    if (inlineImg) {
+      // create an array
+      str = new FixedLengthEncoder(str, len);
+      if (globalParams->getPSASCIIHex()) {
+       str = new ASCIIHexEncoder(str);
+      } else {
+       str = new ASCII85Encoder(str);
+      }
+      str->reset();
+      line = col = 0;
+      writePS("[<~");
+      do {
+       do {
+         c = str->getChar();
+       } while (c == '\n' || c == '\r');
+       if (c == '~' || c == EOF) {
+         break;
+       }
+       if (c == 'z') {
+         writePSChar(c);
+         ++col;
+       } else {
+         writePSChar(c);
+         ++col;
+         for (i = 1; i <= 4; ++i) {
+           do {
+             c = str->getChar();
+           } while (c == '\n' || c == '\r');
+           if (c == '~' || c == EOF) {
+             break;
+           }
+           writePSChar(c);
+           ++col;
+         }
+       }
+       // each line is: "dup nnnnn <~...data...~> put<eol>"
+       // so max data length = 255 - 20 = 235
+       // chunks are 1 or 4 bytes each, so we have to stop at 232
+       // but make it 225 just to be safe
+       if (col > 225) {
+         writePS("~>\n");
+         ++line;
+         writePSFmt("<~", line);
+         col = 0;
+       }
+      } while (c != '~' && c != EOF);
+      writePS("~>]\n");
+      writePS("0\n");
+      delete str;
+    } else {
+      // set up to use the array already created by setupImages()
+      writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
+    }
   }
 
   // image dictionary
   writePS("<<\n  /ImageType 1\n");
 
   // width, height, matrix, bits per component
-  writePS("  /Width %d\n", width);
-  writePS("  /Height %d\n", height);
-  writePS("  /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
-  writePS("  /BitsPerComponent %d\n",
-         colorMap ? colorMap->getBits() : 1);
+  writePSFmt("  /Width %d\n", width);
+  writePSFmt("  /Height %d\n", height);
+  writePSFmt("  /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
+  writePSFmt("  /BitsPerComponent %d\n",
+            colorMap ? colorMap->getBits() : 1);
 
   // decode 
   if (colorMap) {
@@ -2347,55 +2509,33 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
     if (colorMap->getColorSpace()->getMode() == csSeparation) {
       //~ this is a kludge -- see comment in dumpColorSpaceL2
       n = (1 << colorMap->getBits()) - 1;
-      writePS("%g %g", colorMap->getDecodeLow(0) * n,
-             colorMap->getDecodeHigh(0) * n);
+      writePSFmt("%g %g", colorMap->getDecodeLow(0) * n,
+                colorMap->getDecodeHigh(0) * n);
     } else {
       numComps = colorMap->getNumPixelComps();
       for (i = 0; i < numComps; ++i) {
        if (i > 0) {
          writePS(" ");
        }
-       writePS("%g %g", colorMap->getDecodeLow(i),
-               colorMap->getDecodeHigh(i));
+       writePSFmt("%g %g", colorMap->getDecodeLow(i),
+                  colorMap->getDecodeHigh(i));
       }
     }
     writePS("]\n");
   } else {
-    writePS("  /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
+    writePSFmt("  /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
   }
 
   if (mode == psModeForm || inType3Char) {
 
-    if (inlineImg) {
-
-      // data source
-      writePS("  /DataSource <~\n");
-
-      // write image data stream, using ASCII85 encode filter
-      str = new FixedLengthEncoder(str, len);
-      if (globalParams->getPSASCIIHex()) {
-       str = new ASCIIHexEncoder(str);
-      } else {
-       str = new ASCII85Encoder(str);
-      }
-      str->reset();
-      while ((c = str->getChar()) != EOF) {
-       writePSChar(c);
-      }
-      writePSChar('\n');
-      delete str;
-
-    } else {
-      writePS("  /DataSource { 2 copy get exch 1 add exch }\n");
-    }
+    // data source
+    writePS("  /DataSource { 2 copy get exch 1 add exch }\n");
 
     // end of image dictionary
-    writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
+    writePSFmt(">>\n%s\n", colorMap ? "image" : "imagemask");
 
     // get rid of the array and index
-    if (!inlineImg) {
-      writePS("pop pop\n");
-    }
+    writePS("pop pop\n");
 
   } else {
 
@@ -2412,14 +2552,14 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
       useCompressed = gTrue;
     }
     if (useASCII) {
-      writePS("    /ASCII%sDecode filter\n",
-             globalParams->getPSASCIIHex() ? "Hex" : "85");
+      writePSFmt("    /ASCII%sDecode filter\n",
+                globalParams->getPSASCIIHex() ? "Hex" : "85");
     }
     if (useRLE) {
       writePS("    /RunLengthDecode filter\n");
     }
     if (useCompressed) {
-      writePS("%s", s->getCString());
+      writePS(s->getCString());
     }
     if (s) {
       delete s;
@@ -2465,7 +2605,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
       // +6/7 for "pdfIm\n" / "pdfImM\n"
       // +8 for newline + trailer
       n += colorMap ? 14 : 15;
-      writePS("%%%%BeginData: %d Hex Bytes\n", n);
+      writePSFmt("%%%%BeginData: %d Hex Bytes\n", n);
     }
 #endif
     if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
@@ -2473,10 +2613,11 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
       color.c[0] = 1;
       sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
       sepCS->getCMYK(&color, &cmyk);
-      writePS("%g %g %g %g (%s) pdfImSep\n",
-             cmyk.c, cmyk.m, cmyk.y, cmyk.k, sepCS->getName()->getCString());
+      writePSFmt("%g %g %g %g (%s) pdfImSep\n",
+                cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+                sepCS->getName()->getCString());
     } else {
-      writePS("%s\n", colorMap ? "pdfIm" : "pdfImM");
+      writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM");
     }
 
     // copy the stream data
@@ -2488,10 +2629,10 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 
     // add newline and trailer to the end
     writePSChar('\n');
-    writePS("%%-EOD-\n");
+    writePS("%-EOD-\n");
 #if OPI_SUPPORT
     if (opi13Nest) {
-      writePS("%%%%EndData\n");
+      writePS("%%EndData\n");
     }
 #endif
 
@@ -2508,11 +2649,14 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
   GfxLabColorSpace *labCS;
   GfxIndexedColorSpace *indexedCS;
   GfxSeparationColorSpace *separationCS;
-  Guchar *lookup;
+  GfxColorSpace *baseCS;
+  Guchar *lookup, *p;
   double x[gfxColorMaxComps], y[gfxColorMaxComps];
   GfxColor color;
   GfxCMYK cmyk;
-  int n, numComps;
+  Function *func;
+  int n, numComps, numAltComps;
+  int byte;
   int i, j, k;
 
   switch (colorSpace->getMode()) {
@@ -2525,16 +2669,16 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
   case csCalGray:
     calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
     writePS("[/CIEBasedA <<\n");
-    writePS(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
-    writePS(" /MatrixA [%g %g %g]\n",
-           calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
-           calGrayCS->getWhiteZ());
-    writePS(" /WhitePoint [%g %g %g]\n",
-           calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
-           calGrayCS->getWhiteZ());
-    writePS(" /BlackPoint [%g %g %g]\n",
-           calGrayCS->getBlackX(), calGrayCS->getBlackY(),
-           calGrayCS->getBlackZ());
+    writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
+    writePSFmt(" /MatrixA [%g %g %g]\n",
+              calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+              calGrayCS->getWhiteZ());
+    writePSFmt(" /WhitePoint [%g %g %g]\n",
+              calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+              calGrayCS->getWhiteZ());
+    writePSFmt(" /BlackPoint [%g %g %g]\n",
+              calGrayCS->getBlackX(), calGrayCS->getBlackY(),
+              calGrayCS->getBlackZ());
     writePS(">>]");
     processColors |= psProcessBlack;
     break;
@@ -2547,21 +2691,21 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
   case csCalRGB:
     calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
     writePS("[/CIEBasedABC <<\n");
-    writePS(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
-           calRGBCS->getGammaR(), calRGBCS->getGammaG(),
-           calRGBCS->getGammaB());
-    writePS(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
-           calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
-           calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
-           calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
-           calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
-           calRGBCS->getMatrix()[8]);
-    writePS(" /WhitePoint [%g %g %g]\n",
-           calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
-           calRGBCS->getWhiteZ());
-    writePS(" /BlackPoint [%g %g %g]\n",
-           calRGBCS->getBlackX(), calRGBCS->getBlackY(),
-           calRGBCS->getBlackZ());
+    writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
+              calRGBCS->getGammaR(), calRGBCS->getGammaG(),
+              calRGBCS->getGammaB());
+    writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
+              calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
+              calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
+              calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
+              calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
+              calRGBCS->getMatrix()[8]);
+    writePSFmt(" /WhitePoint [%g %g %g]\n",
+              calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
+              calRGBCS->getWhiteZ());
+    writePSFmt(" /BlackPoint [%g %g %g]\n",
+              calRGBCS->getBlackX(), calRGBCS->getBlackY(),
+              calRGBCS->getBlackZ());
     writePS(">>]");
     processColors |= psProcessCMYK;
     break;
@@ -2574,25 +2718,25 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
   case csLab:
     labCS = (GfxLabColorSpace *)colorSpace;
     writePS("[/CIEBasedABC <<\n");
-    writePS(" /RangeABC [0 100 %g %g %g %g]\n",
-           labCS->getAMin(), labCS->getAMax(),
-           labCS->getBMin(), labCS->getBMax());
+    writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n",
+              labCS->getAMin(), labCS->getAMax(),
+              labCS->getBMin(), labCS->getBMax());
     writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
     writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
     writePS(" /DecodeLMN\n");
     writePS("   [{dup 6 29 div ge {dup dup mul mul}\n");
-    writePS("     {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
-           labCS->getWhiteX());
+    writePSFmt("     {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
+              labCS->getWhiteX());
     writePS("    {dup 6 29 div ge {dup dup mul mul}\n");
-    writePS("     {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
-           labCS->getWhiteY());
+    writePSFmt("     {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
+              labCS->getWhiteY());
     writePS("    {dup 6 29 div ge {dup dup mul mul}\n");
-    writePS("     {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
-           labCS->getWhiteZ());
-    writePS(" /WhitePoint [%g %g %g]\n",
-           labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
-    writePS(" /BlackPoint [%g %g %g]\n",
-           labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
+    writePSFmt("     {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
+              labCS->getWhiteZ());
+    writePSFmt(" /WhitePoint [%g %g %g]\n",
+              labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
+    writePSFmt(" /BlackPoint [%g %g %g]\n",
+              labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
     writePS(">>]");
     processColors |= psProcessCMYK;
     break;
@@ -2603,23 +2747,52 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
 
   case csIndexed:
     indexedCS = (GfxIndexedColorSpace *)colorSpace;
+    baseCS = indexedCS->getBase();
     writePS("[/Indexed ");
-    dumpColorSpaceL2(indexedCS->getBase());
+    dumpColorSpaceL2(baseCS);
     n = indexedCS->getIndexHigh();
-    numComps = indexedCS->getBase()->getNComps();
+    numComps = baseCS->getNComps();
     lookup = indexedCS->getLookup();
-    writePS(" %d <\n", n);
-    for (i = 0; i <= n; i += 8) {
-      writePS("  ");
-      for (j = i; j < i+8 && j <= n; ++j) {
-       for (k = 0; k < numComps; ++k) {
-         writePS("%02x", lookup[j * numComps + k]);
+    writePSFmt(" %d <\n", n);
+    if (baseCS->getMode() == csDeviceN) {
+      func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
+      numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
+      p = lookup;
+      for (i = 0; i <= n; i += 8) {
+       writePS("  ");
+       for (j = i; j < i+8 && j <= n; ++j) {
+         for (k = 0; k < numComps; ++k) {
+           x[k] = *p++ / 255.0;
+         }
+         func->transform(x, y);
+         for (k = 0; k < numAltComps; ++k) {
+           byte = (int)(y[k] * 255 + 0.5);
+           if (byte < 0) {
+             byte = 0;
+           } else if (byte > 255) {
+             byte = 255;
+           }
+           writePSFmt("%02x", byte);
+         }
+         color.c[0] = j;
+         indexedCS->getCMYK(&color, &cmyk);
+         addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
        }
-       color.c[0] = j;
-       indexedCS->getCMYK(&color, &cmyk);
-       addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+       writePS("\n");
+      }
+    } else {
+      for (i = 0; i <= n; i += 8) {
+       writePS("  ");
+       for (j = i; j < i+8 && j <= n; ++j) {
+         for (k = 0; k < numComps; ++k) {
+           writePSFmt("%02x", lookup[j * numComps + k]);
+         }
+         color.c[0] = j;
+         indexedCS->getCMYK(&color, &cmyk);
+         addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+       }
+       writePS("\n");
       }
-      writePS("\n");
     }
     writePS(">]");
     break;
@@ -2639,7 +2812,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
        x[0] = (double)j / 255.0;
        separationCS->getFunc()->transform(x, y);
        for (k = 0; k < numComps; ++k) {
-         writePS("%02x", (int)(255 * y[k] + 0.5));
+         writePSFmt("%02x", (int)(255 * y[k] + 0.5));
        }
       }
       writePS("\n");
@@ -2686,20 +2859,20 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
   int w, h;
   int i;
 
-  writePS("%%%%BeginOPI: 2.0\n");
-  writePS("%%%%Distilled\n");
+  writePS("%%BeginOPI: 2.0\n");
+  writePS("%%Distilled\n");
 
   dict->lookup("F", &obj1);
   if (getFileSpec(&obj1, &obj2)) {
-    writePS("%%%%ImageFileName: %s\n",
-           obj2.getString()->getCString());
+    writePSFmt("%%%%ImageFileName: %s\n",
+              obj2.getString()->getCString());
     obj2.free();
   }
   obj1.free();
 
   dict->lookup("MainImage", &obj1);
   if (obj1.isString()) {
-    writePS("%%%%MainImage: %s\n", obj1.getString()->getCString());
+    writePSFmt("%%%%MainImage: %s\n", obj1.getString()->getCString());
   }
   obj1.free();
 
@@ -2714,7 +2887,7 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
     obj1.arrayGet(1, &obj2);
     height = obj2.getNum();
     obj2.free();
-    writePS("%%%%ImageDimensions: %g %g\n", width, height);
+    writePSFmt("%%%%ImageDimensions: %g %g\n", width, height);
   }
   obj1.free();
 
@@ -2732,31 +2905,31 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
     obj1.arrayGet(3, &obj2);
     bottom = obj2.getNum();
     obj2.free();
-    writePS("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
+    writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
   }
   obj1.free();
 
   dict->lookup("Overprint", &obj1);
   if (obj1.isBool()) {
-    writePS("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
+    writePSFmt("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
   }
   obj1.free();
 
   dict->lookup("Inks", &obj1);
   if (obj1.isName()) {
-    writePS("%%%%ImageInks: %s\n", obj1.getName());
+    writePSFmt("%%%%ImageInks: %s\n", obj1.getName());
   } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
     obj1.arrayGet(0, &obj2);
     if (obj2.isName()) {
-      writePS("%%%%ImageInks: %s %d",
-             obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
+      writePSFmt("%%%%ImageInks: %s %d",
+                obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
       for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
        obj1.arrayGet(i, &obj3);
        obj1.arrayGet(i+1, &obj4);
        if (obj3.isString() && obj4.isNum()) {
          writePS(" ");
          writePSString(obj3.getString());
-         writePS(" %g", obj4.getNum());
+         writePSFmt(" %g", obj4.getNum());
        }
        obj3.free();
        obj4.free();
@@ -2769,7 +2942,7 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
 
   writePS("gsave\n");
 
-  writePS("%%%%BeginIncludedImage\n");
+  writePS("%%BeginIncludedImage\n");
 
   dict->lookup("IncludedImageDimensions", &obj1);
   if (obj1.isArray() && obj1.arrayGetLength() == 2) {
@@ -2779,13 +2952,13 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
     obj1.arrayGet(1, &obj2);
     h = obj2.getInt();
     obj2.free();
-    writePS("%%%%IncludedImageDimensions: %d %d\n", w, h);
+    writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w, h);
   }
   obj1.free();
 
   dict->lookup("IncludedImageQuality", &obj1);
   if (obj1.isNum()) {
-    writePS("%%%%IncludedImageQuality: %g\n", obj1.getNum());
+    writePSFmt("%%%%IncludedImageQuality: %g\n", obj1.getNum());
   }
   obj1.free();
 
@@ -2807,8 +2980,8 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
 
   dict->lookup("F", &obj1);
   if (getFileSpec(&obj1, &obj2)) {
-    writePS("%%ALDImageFileName: %s\n",
-           obj2.getString()->getCString());
+    writePSFmt("%%ALDImageFileName: %s\n",
+              obj2.getString()->getCString());
     obj2.free();
   }
   obj1.free();
@@ -2827,7 +3000,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
     obj1.arrayGet(3, &obj2);
     bottom = obj2.getInt();
     obj2.free();
-    writePS("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
+    writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
   }
   obj1.free();
 
@@ -2847,7 +3020,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
     obj2.free();
     obj1.arrayGet(4, &obj2);
     if (obj2.isString()) {
-      writePS("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
+      writePSFmt("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
       writePSString(obj2.getString());
       writePS("\n");
     }
@@ -2857,7 +3030,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
 
   dict->lookup("ColorType", &obj1);
   if (obj1.isName()) {
-    writePS("%%ALDImageColorType: %s\n", obj1.getName());
+    writePSFmt("%%ALDImageColorType: %s\n", obj1.getName());
   }
   obj1.free();
 
@@ -2878,20 +3051,20 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
     obj1.arrayGet(3, &obj2);
     lry = obj2.getNum();
     obj2.free();
-    writePS("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
+    writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
   }
   obj1.free();
 
   dict->lookup("GrayMap", &obj1);
   if (obj1.isArray()) {
-    writePS("%%ALDImageGrayMap:");
+    writePS("%ALDImageGrayMap:");
     for (i = 0; i < obj1.arrayGetLength(); i += 16) {
       if (i > 0) {
-       writePS("\n%%%%+");
+       writePS("\n%%+");
       }
       for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
        obj1.arrayGet(i+j, &obj2);
-       writePS(" %d", obj2.getInt());
+       writePSFmt(" %d", obj2.getInt());
        obj2.free();
       }
     }
@@ -2901,7 +3074,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
 
   dict->lookup("ID", &obj1);
   if (obj1.isString()) {
-    writePS("%%ALDImageID: %s\n", obj1.getString()->getCString());
+    writePSFmt("%%ALDImageID: %s\n", obj1.getString()->getCString());
   }
   obj1.free();
 
@@ -2913,13 +3086,13 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
     obj1.arrayGet(1, &obj2);
     bits = obj2.getInt();
     obj2.free();
-    writePS("%%ALDImageType: %d %d\n", samples, bits);
+    writePSFmt("%%ALDImageType: %d %d\n", samples, bits);
   }
   obj1.free();
 
   dict->lookup("Overprint", &obj1);
   if (obj1.isBool()) {
-    writePS("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
+    writePSFmt("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
   }
   obj1.free();
 
@@ -2953,8 +3126,8 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
     opiTransform(state, ulx, uly, &tulx, &tuly);
     opiTransform(state, urx, ury, &turx, &tury);
     opiTransform(state, lrx, lry, &tlrx, &tlry);
-    writePS("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
-           tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
+    writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
+              tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
     obj2.free();
   }
   obj1.free();
@@ -2967,7 +3140,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
     obj1.arrayGet(1, &obj2);
     vert = obj2.getNum();
     obj2.free();
-    writePS("%%ALDImageResoution: %g %g\n", horiz, vert);
+    writePSFmt("%%ALDImageResoution: %g %g\n", horiz, vert);
     obj2.free();
   }
   obj1.free();
@@ -2980,7 +3153,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
     obj1.arrayGet(1, &obj2);
     height = obj2.getInt();
     obj2.free();
-    writePS("%%ALDImageDimensions: %d %d\n", width, height);
+    writePSFmt("%%ALDImageDimensions: %d %d\n", width, height);
   }
   obj1.free();
 
@@ -2989,17 +3162,17 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
 
   dict->lookup("Tint", &obj1);
   if (obj1.isNum()) {
-    writePS("%%ALDImageTint: %g\n", obj1.getNum());
+    writePSFmt("%%ALDImageTint: %g\n", obj1.getNum());
   }
   obj1.free();
 
   dict->lookup("Transparency", &obj1);
   if (obj1.isBool()) {
-    writePS("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
+    writePSFmt("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
   }
   obj1.free();
 
-  writePS("%%%%BeginObject: image\n");
+  writePS("%%BeginObject: image\n");
   writePS("opiMatrix2 setmatrix\n");
   ++opi13Nest;
 }
@@ -3029,8 +3202,8 @@ void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
   if (globalParams->getPSOPI()) {
     opiDict->lookup("2.0", &dict);
     if (dict.isDict()) {
-      writePS("%%%%EndIncludedImage\n");
-      writePS("%%%%EndOPI\n");
+      writePS("%%EndIncludedImage\n");
+      writePS("%%EndOPI\n");
       writePS("grestore\n");
       --opi20Nest;
       dict.free();
@@ -3038,7 +3211,7 @@ void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
       dict.free();
       opiDict->lookup("1.3", &dict);
       if (dict.isDict()) {
-       writePS("%%%%EndObject\n");
+       writePS("%%EndObject\n");
        writePS("restore\n");
        --opi13Nest;
       }
@@ -3079,7 +3252,7 @@ GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) {
 #endif // OPI_SUPPORT
 
 void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
-  writePS("%g %g setcharwidth\n", wx, wy);
+  writePSFmt("%g %g setcharwidth\n", wx, wy);
   writePS("q\n");
 }
 
@@ -3112,18 +3285,34 @@ void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
   str->close();
 }
 
-void PSOutputDev::writePS(const char *fmt, ...) {
+void PSOutputDev::writePSChar(char c) {
+  if (t3String) {
+    t3String->append(c);
+  } else {
+    (*outputFunc)(outputStream, &c, 1);
+  }
+}
+
+void PSOutputDev::writePS(char *s) {
+  if (t3String) {
+    t3String->append(s);
+  } else {
+    (*outputFunc)(outputStream, s, strlen(s));
+  }
+}
+
+void PSOutputDev::writePSFmt(const char *fmt, ...) {
   va_list args;
   char buf[512];
 
   va_start(args, fmt);
+  vsprintf(buf, fmt, args);
+  va_end(args);
   if (t3String) {
-    vsprintf(buf, fmt, args);
     t3String->append(buf);
   } else {
-    vfprintf(f, fmt, args);
+    (*outputFunc)(outputStream, buf, strlen(buf));
   }
-  va_end(args);
 }
 
 void PSOutputDev::writePSString(GString *s) {
@@ -3137,11 +3326,11 @@ void PSOutputDev::writePSString(GString *s) {
       writePSChar('\\');
       writePSChar((char)*p);
     } else if (*p < 0x20 || *p >= 0x80) {
+      sprintf(buf, "\\%03o", *p);
       if (t3String) {
-       sprintf(buf, "\\%03o", *p);
        t3String->append(buf);
       } else {
-       fprintf(f, "\\%03o", *p);
+       (*outputFunc)(outputStream, buf, strlen(buf));
       }
     } else {
       writePSChar((char)*p);
@@ -3150,11 +3339,20 @@ void PSOutputDev::writePSString(GString *s) {
   writePSChar(')');
 }
 
-void PSOutputDev::writePSChar(char c) {
-  if (t3String) {
-    t3String->append(c);
-  } else {
-    fputc(c, f);
+void PSOutputDev::writePSName(char *s) {
+  char *p;
+  char c;
+
+  p = s;
+  while ((c = *p++)) {
+    if (c <= (char)0x20 || c >= (char)0x7f ||
+       c == '(' || c == ')' || c == '<' || c == '>' ||
+       c == '[' || c == ']' || c == '{' || c == '}' ||
+       c == '/' || c == '%') {
+      writePSFmt("#%02x", c & 0xff);
+    } else {
+      writePSChar(c);
+    }
   }
 }
 
@@ -3165,6 +3363,15 @@ GString *PSOutputDev::filterPSName(GString *name) {
   char c;
 
   name2 = new GString();
+
+  // ghostscript chokes on names that begin with out-of-limits
+  // numbers, e.g., 1e4foo is handled correctly (as a name), but
+  // 1e999foo generates a limitcheck error
+  c = name->getChar(0);
+  if (c >= '0' && c <= '9') {
+    name2->append('f');
+  }
+
   for (i = 0; i < name->getLength(); ++i) {
     c = name->getChar(i);
     if (c <= (char)0x20 || c >= (char)0x7f ||