[poppler] Branch 'xpdf303merge' - poppler/GfxFont.cc poppler/GlobalParams.cc poppler/GlobalParams.h poppler/GlobalParamsWin.cc poppler/Hints.cc poppler/Parser.cc poppler/Parser.h poppler/PreScanOutputDev.cc poppler/PreScanOutputDev.h poppler/PSOutputDev.cc poppler/PSOutputDev.h poppler/XRef.cc poppler/XRef.h utils/pdftops.cc

Albert Astals Cid aacid at kemper.freedesktop.org
Sun Feb 5 13:57:55 PST 2012


 poppler/GfxFont.cc          |    4 
 poppler/GlobalParams.cc     |   95 +-
 poppler/GlobalParams.h      |   18 
 poppler/GlobalParamsWin.cc  |   16 
 poppler/Hints.cc            |    2 
 poppler/PSOutputDev.cc      | 1814 ++++++++++++++++++++++----------------------
 poppler/PSOutputDev.h       |   51 -
 poppler/Parser.cc           |   13 
 poppler/Parser.h            |    7 
 poppler/PreScanOutputDev.cc |   70 +
 poppler/PreScanOutputDev.h  |   16 
 poppler/XRef.cc             |   91 +-
 poppler/XRef.h              |    3 
 utils/pdftops.cc            |    2 
 14 files changed, 1231 insertions(+), 971 deletions(-)

New commits:
commit 6ee907f291427b8751a872b31210bf32e8d2b722
Author: Albert Astals Cid <aacid at kde.org>
Date:   Sun Feb 5 22:57:25 2012 +0100

    [xpdf303] More merges from Thomas, basically PSOutputDev and some other small stuff

diff --git a/poppler/GfxFont.cc b/poppler/GfxFont.cc
index c839ad4..4e29c36 100644
--- a/poppler/GfxFont.cc
+++ b/poppler/GfxFont.cc
@@ -729,7 +729,7 @@ GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) {
   if (!isCIDFont()) {
 
     //----- 8-bit PS resident font
-    if (ps) {
+    if (name && ps) {
       if ((path = globalParams->getPSResidentFont(name))) {
 	fontLoc = new GfxFontLoc();
 	fontLoc->locType = gfxFontLocResident;
@@ -756,7 +756,7 @@ GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) {
     substName = new GooString(base14SubstFonts[substIdx]);
     if (ps) {
       error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'",
-	    base14SubstFonts[substIdx], name);
+	    base14SubstFonts[substIdx], name ? name : new GooString("null"));
       fontLoc = new GfxFontLoc();
       fontLoc->locType = gfxFontLocResident;
       fontLoc->fontType = fontType1;
diff --git a/poppler/GlobalParams.cc b/poppler/GlobalParams.cc
index ab399db..bfde306 100644
--- a/poppler/GlobalParams.cc
+++ b/poppler/GlobalParams.cc
@@ -582,6 +582,10 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
   psOPI = gFalse;
   psASCIIHex = gFalse;
   psBinary = gFalse;
+  psUncompressPreloadedImages = gFalse;
+  psRasterResolution = 300;
+  psRasterMono = gFalse;
+  psAlwaysRasterize = gFalse;
   textEncoding = new GooString("UTF-8");
 #if defined(_WIN32)
   textEOL = eolDOS;
@@ -596,6 +600,7 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
   disableFreeTypeHinting = gFalse;
   antialias = gTrue;
   vectorAntialias = gTrue;
+  antialiasPrinting = gFalse;
   strokeAdjust = gTrue;
   screenType = screenUnset;
   screenSize = -1;
@@ -610,7 +615,6 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
   printCommands = gFalse;
   profileCommands = gFalse;
   errQuiet = gFalse;
-  splashResolution = 0.0;
 
   cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize);
   unicodeToUnicodeCache =
@@ -1559,6 +1563,42 @@ GBool GlobalParams::getPSBinary() {
   return binary;
 }
 
+GBool GlobalParams::getPSUncompressPreloadedImages() {
+  GBool ah;
+
+  lockGlobalParams;
+  ah = psUncompressPreloadedImages;
+  unlockGlobalParams;
+  return ah;
+}
+
+double GlobalParams::getPSRasterResolution() {
+  double res;
+
+  lockGlobalParams;
+  res = psRasterResolution;
+  unlockGlobalParams;
+  return res;
+}
+
+GBool GlobalParams::getPSRasterMono() {
+  GBool mono;
+
+  lockGlobalParams;
+  mono = psRasterMono;
+  unlockGlobalParams;
+  return mono;
+}
+
+GBool GlobalParams::getPSAlwaysRasterize() {
+  GBool rast;
+
+  lockGlobalParams;
+  rast = psAlwaysRasterize;
+  unlockGlobalParams;
+  return rast;
+}
+
 GooString *GlobalParams::getTextEncodingName() {
   GooString *s;
 
@@ -1631,6 +1671,15 @@ GBool GlobalParams::getVectorAntialias() {
   return f;
 }
 
+GBool GlobalParams::getAntialiasPrinting() {
+  GBool f;
+
+  lockGlobalParams;
+  f = antialiasPrinting;
+  unlockGlobalParams;
+  return f;
+}
+
 GBool GlobalParams::getStrokeAdjust() {
   GBool f;
 
@@ -1745,14 +1794,6 @@ GBool GlobalParams::getErrQuiet() {
   return errQuiet;
 }
 
-double GlobalParams::getSplashResolution() {
-  double r;
-  lockGlobalParams;
-  r = splashResolution;
-  unlockGlobalParams;
-  return r;
-}
-
 CharCodeToUnicode *GlobalParams::getCIDToUnicode(GooString *collection) {
   GooString *fileName;
   CharCodeToUnicode *ctu;
@@ -1944,6 +1985,30 @@ void GlobalParams::setPSBinary(GBool binary) {
   unlockGlobalParams;
 }
 
+void GlobalParams::setPSUncompressPreloadedImages(GBool uncomp) {
+  lockGlobalParams;
+  psUncompressPreloadedImages = uncomp;
+  unlockGlobalParams;
+}
+
+void GlobalParams::setPSRasterResolution(double res) {
+  lockGlobalParams;
+  psRasterResolution = res;
+  unlockGlobalParams;
+}
+
+void GlobalParams::setPSRasterMono(GBool mono) {
+  lockGlobalParams;
+  psRasterMono = mono;
+  unlockGlobalParams;
+}
+
+void GlobalParams::setPSAlwaysRasterize(GBool always) {
+  lockGlobalParams;
+  psAlwaysRasterize = always;
+  unlockGlobalParams;
+}
+
 void GlobalParams::setTextEncoding(char *encodingName) {
   lockGlobalParams;
   delete textEncoding;
@@ -2015,6 +2080,12 @@ GBool GlobalParams::setVectorAntialias(char *s) {
   return ok;
 }
 
+void GlobalParams::setAntialiasPrinting(GBool anti) {
+  lockGlobalParams;
+  antialiasPrinting = anti;
+  unlockGlobalParams;
+}
+
 void GlobalParams::setStrokeAdjust(GBool adjust)
 {
   lockGlobalParams;
@@ -2107,12 +2178,6 @@ void GlobalParams::setErrQuiet(GBool errQuietA) {
   unlockGlobalParams;
 }
 
-void GlobalParams::setSplashResolution(double SplashResolutionA) {
-  lockGlobalParams;
-  splashResolution = SplashResolutionA;
-  unlockGlobalParams;
-}
-
 void GlobalParams::addSecurityHandler(XpdfSecurityHandler *handler) {
 #ifdef ENABLE_PLUGINS
   lockGlobalParams;
diff --git a/poppler/GlobalParams.h b/poppler/GlobalParams.h
index 35f4473..a861ffd 100644
--- a/poppler/GlobalParams.h
+++ b/poppler/GlobalParams.h
@@ -165,6 +165,10 @@ public:
   GBool getPSOPI();
   GBool getPSASCIIHex();
   GBool getPSBinary();
+  GBool getPSUncompressPreloadedImages();
+  double getPSRasterResolution();
+  GBool getPSRasterMono();
+  GBool getPSAlwaysRasterize();
   GooString *getTextEncodingName();
   EndOfLineKind getTextEOL();
   GBool getTextPageBreaks();
@@ -173,6 +177,7 @@ public:
   GBool getDisableFreeTypeHinting();
   GBool getAntialias();
   GBool getVectorAntialias();
+  GBool getAntialiasPrinting();
   GBool getStrokeAdjust();
   ScreenType getScreenType();
   int getScreenSize();
@@ -217,6 +222,10 @@ public:
   void setPSOPI(GBool opi);
   void setPSASCIIHex(GBool hex);
   void setPSBinary(GBool binary);
+  void setPSUncompressPreloadedImages(GBool uncomp);
+  void setPSRasterResolution(double res);
+  void setPSRasterMono(GBool mono);
+  void setPSAlwaysRasterize(GBool always);
   void setTextEncoding(char *encodingName);
   GBool setTextEOL(char *s);
   void setTextPageBreaks(GBool pageBreaks);
@@ -225,6 +234,7 @@ public:
   GBool setDisableFreeTypeHinting(char *s);
   GBool setAntialias(char *s);
   GBool setVectorAntialias(char *s);
+  void setAntialiasPrinting(GBool print);
   void setStrokeAdjust(GBool strokeAdjust);
   void setScreenType(ScreenType st);
   void setScreenSize(int size);
@@ -239,7 +249,6 @@ public:
   void setPrintCommands(GBool printCommandsA);
   void setProfileCommands(GBool profileCommandsA);
   void setErrQuiet(GBool errQuietA);
-  void setSplashResolution(double splashResolutionA);
 
   //----- security handlers
 
@@ -313,6 +322,12 @@ private:
   GBool psOPI;			// generate PostScript OPI comments?
   GBool psASCIIHex;		// use ASCIIHex instead of ASCII85?
   GBool psBinary;		// use binary instead of hex
+  GBool psUncompressPreloadedImages;  // uncompress all preloaded images
+  double psRasterResolution;	// PostScript rasterization resolution (dpi)
+  GBool psRasterMono;		// true to do PostScript rasterization
+				//   in monochrome (gray); false to do it
+				//   in color (RGB/CMYK)
+  GBool psAlwaysRasterize;	// force PostScript rasterization
   GooString *textEncoding;	// encoding (unicodeMap) to use for text
 				//   output
   EndOfLineKind textEOL;	// type of EOL marker to use for text
@@ -323,6 +338,7 @@ private:
   GBool disableFreeTypeHinting;	// FreeType disable hinting flag
   GBool antialias;		// anti-aliasing enable flag
   GBool vectorAntialias;	// vector anti-aliasing enable flag
+  GBool antialiasPrinting;	// allow anti-aliasing when printing
   GBool strokeAdjust;		// stroke adjustment enable flag
   ScreenType screenType;	// halftone screen type
   int screenSize;		// screen matrix size
diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc
index 54ce4f7..100b7a2 100644
--- a/poppler/GlobalParamsWin.cc
+++ b/poppler/GlobalParamsWin.cc
@@ -60,9 +60,9 @@ description for all fonts available in Windows. That's how MuPDF works.
 #define DEFAULT_SUBSTITUTE_FONT "Helvetica"
 
 static struct {
-    char *name;
-    char *t1FileName;
-    char *ttFileName;
+    const char *name;
+    const char *t1FileName;
+    const char *ttFileName;
 } displayFontTab[] = {
     {"Courier",               "n022003l.pfb", "cour.ttf"},
     {"Courier-Bold",          "n022004l.pfb", "courbd.ttf"},
@@ -253,7 +253,8 @@ void SysFontList::scanWindowsFonts(GooString *winFontDir) {
 	data[dataLen] = '\0';
 	n = strlen(data);
 	if (!strcasecmp(data + n - 4, ".ttf") ||
-	    !strcasecmp(data + n - 4, ".ttc")) {
+	    !strcasecmp(data + n - 4, ".ttc") ||
+	    !strcasecmp(data + n - 4, ".otf")) {
 	  fontPath = new GooString(data);
 	  if (!(dataLen >= 3 && data[1] == ':' && data[2] == '\\')) {
 	    fontPath->insert(0, '\\');
@@ -301,6 +302,11 @@ SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum,
     n -= 11;
   }
 
+  // remove trailing ' (OpenType)'
+  if (n > 11 && !strncmp(name + n - 11, " (OpenType)", 11)) {
+    n -= 11;
+  }
+
   // remove trailing ' Italic'
   if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) {
     n -= 7;
@@ -401,7 +407,7 @@ GooString *GlobalParams::findSystemFontFile(GfxFont *font,
     *fontNum = fi->fontNum;
   } else {
     GooString *substFontName = new GooString(findSubstituteName(fontName->getCString()));
-    error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', subst is '{0:s}'", fontName, substFontName);
+    error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', subst is '{1:t}'", fontName, substFontName);
     if ((fi = sysFonts->find(substFontName, gFalse))) {
       path = fi->path->copy();
       *type = fi->type;
diff --git a/poppler/Hints.cc b/poppler/Hints.cc
index df066c6..46bce80 100644
--- a/poppler/Hints.cc
+++ b/poppler/Hints.cc
@@ -134,7 +134,7 @@ void Hints::readTables(BaseStream *str, Linearization *linearization, XRef *xref
   if (parser->getObj(&obj)->isInt() &&
      (num = obj.getInt(), obj.free(), parser->getObj(&obj)->isInt()) &&
      (gen = obj.getInt(), obj.free(), parser->getObj(&obj)->isCmd("obj")) &&
-     (obj.free(), parser->getObj(&obj,
+     (obj.free(), parser->getObj(&obj, gFalse,
          secHdlr ? secHdlr->getFileKey() : (Guchar *)NULL,
          secHdlr ? secHdlr->getEncAlgorithm() : cryptRC4,
          secHdlr ? secHdlr->getFileKeyLength() : 0,
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index cf385be..7dbac8a 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -86,8 +86,8 @@
 
 //------------------------------------------------------------------------
 
-// Resolution at which pages with transparency will be rasterized.
-#define defaultSplashDPI 300
+// Max size of a slice when rasterizing pages, in pixels.
+#define rasterizationSliceSize 20000000
 
 //------------------------------------------------------------------------
 // PostScript prolog and setup
@@ -113,16 +113,24 @@ static const char *prolog[] = {
   "  } for",
   "~123sn",
   "/pdfSetup {",
-  "  3 1 roll 2 array astore",
   "  /setpagedevice where {",
-  "    pop 3 dict begin",
+  "    pop 2 dict begin",
+  "      /Policies 1 dict dup begin /PageSize 6 def end def",
+  "      { /Duplex true def } if",
+  "    currentdict end setpagedevice",
+  "  } {",
+  "    pop",
+  "  } ifelse",
+  "} def",
+  "/pdfSetupPaper {",
+  "  2 array astore",
+  "  /setpagedevice where {",
+  "    pop 2 dict begin",
   "      /PageSize exch def",
   "      /ImagingBBox null def",
-  "      /Policies 1 dict dup begin /PageSize 3 def end def",
-  "      { /Duplex true def } if",
   "    currentdict end setpagedevice",
   "  } {",
-  "    pop pop",
+  "    pop",
   "  } ifelse",
   "} def",
   "~1sn",
@@ -410,82 +418,82 @@ static const char *prolog[] = {
   "/Td { pdfTextMat transform moveto } def",
   "/Tm { /pdfTextMat exch def } def",
   "% text string operators",
+  "/xyshow where {",
+  "  pop",
+  "  /xyshow2 {",
+  "    dup length array",
+  "    0 2 2 index length 1 sub {",
+  "      2 index 1 index 2 copy get 3 1 roll 1 add get",
+  "      pdfTextMat dtransform",
+  "      4 2 roll 2 copy 6 5 roll put 1 add 3 1 roll dup 4 2 roll put",
+  "    } for",
+  "    exch pop",
+  "    xyshow",
+  "  } def",
+  "}{",
+  "  /xyshow2 {",
+  "    currentfont /FontType get 0 eq {",
+  "      0 2 3 index length 1 sub {",
+  "        currentpoint 4 index 3 index 2 getinterval show moveto",
+  "        2 copy get 2 index 3 2 roll 1 add get",
+  "        pdfTextMat dtransform rmoveto",
+  "      } for",
+  "    } {",
+  "      0 1 3 index length 1 sub {",
+  "        currentpoint 4 index 3 index 1 getinterval show moveto",
+  "        2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get",
+  "        pdfTextMat dtransform rmoveto",
+  "      } for",
+  "    } ifelse",
+  "    pop pop",
+  "  } def",
+  "} ifelse",
   "/cshow where {",
   "  pop",
-  "  /cshow2 {",
-  "    dup {",
-  "      pop pop",
-  "      1 string dup 0 3 index put 3 index exec",
+  "  /xycp {", // xycharpath
+  "    0 3 2 roll",
+  "    {",
+  "      pop pop currentpoint 3 2 roll",
+  "      1 string dup 0 4 3 roll put false charpath moveto",
+  "      2 copy get 2 index 2 index 1 add get",
+  "      pdfTextMat dtransform rmoveto",
+  "      2 add",
   "    } exch cshow",
   "    pop pop",
   "  } def",
   "}{",
-  "  /cshow2 {",
+  "  /xycp {", // xycharpath
   "    currentfont /FontType get 0 eq {",
-  "      0 2 2 index length 1 sub {",
-  "        2 copy get exch 1 add 2 index exch get",
-  "        2 copy exch 256 mul add",
-  "        2 string dup 0 6 5 roll put dup 1 5 4 roll put",
-  "        3 index exec",
+  "      0 2 3 index length 1 sub {",
+  "        currentpoint 4 index 3 index 2 getinterval false charpath moveto",
+  "        2 copy get 2 index 3 2 roll 1 add get",
+  "        pdfTextMat dtransform rmoveto",
   "      } for",
   "    } {",
-  "      dup {",
-  "        1 string dup 0 3 index put 3 index exec",
-  "      } forall",
+  "      0 1 3 index length 1 sub {",
+  "        currentpoint 4 index 3 index 1 getinterval false charpath moveto",
+  "        2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get",
+  "        pdfTextMat dtransform rmoveto",
+  "      } for",
   "    } ifelse",
   "    pop pop",
   "  } def",
   "} ifelse",
-  "/awcp {", // awidthcharpath
-  "  exch {",
-  "    false charpath",
-  "    5 index 5 index rmoveto",
-  "    6 index eq { 7 index 7 index rmoveto } if",
-  "  } exch cshow2",
-  "  6 {pop} repeat",
-  "} def",
   "/Tj {",
   "  fCol",  // because stringwidth has to draw Type 3 chars
-  "  1 index stringwidth pdfTextMat idtransform pop",
-  "  sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
-  "  pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
-  "  4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
-  "  pdfTextMat dtransform",
-  "  6 5 roll Tj1",
-  "} def",
-  "/Tj16 {",
-  "  fCol",  // because stringwidth has to draw Type 3 chars
-  "  2 index stringwidth pdfTextMat idtransform pop",
-  "  sub exch div",
-  "  pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
-  "  4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
-  "  pdfTextMat dtransform",
-  "  6 5 roll Tj1",
-  "} def",
-  "/Tj16V {",
-  "  fCol",  // because stringwidth has to draw Type 3 chars
-  "  2 index stringwidth pdfTextMat idtransform exch pop",
-  "  sub exch div",
-  "  0 pdfWordSpacing pdfTextMat dtransform 32",
-  "  4 3 roll pdfCharSpacing add 0 exch",
-  "  pdfTextMat dtransform",
-  "  6 5 roll Tj1",
-  "} def",
-  "/Tj1 {",
   "  0 pdfTextRise pdfTextMat dtransform rmoveto",
-  "  currentpoint 8 2 roll",
-  "  pdfTextRender 1 and 0 eq pdfPatternCS not and {",
-  "    6 copy awidthshow",
+  "  currentpoint 4 2 roll",
+  "  pdfTextRender 1 and 0 eq {",
+  "    2 copy xyshow2",
   "  } if",
   "  pdfTextRender 3 and dup 1 eq exch 2 eq or {",
-  "    7 index 7 index moveto",
-  "    6 copy",
+  "    3 index 3 index moveto",
+  "    2 copy",
   "    currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
-  "    false awcp currentpoint stroke moveto",
+  "    xycp currentpoint stroke moveto",
   "  } if",
-  "  pdfTextRender 4 and 0 ne pdfPatternCS or {",
-  "    8 6 roll moveto",
-  "    false awcp",
+  "  pdfTextRender 4 and 0 ne {",
+  "    4 2 roll moveto xycp",
   "    /pdfTextClipPath [ pdfTextClipPath aload pop",
   "      {/moveto cvx}",
   "      {/lineto cvx}",
@@ -494,13 +502,13 @@ static const char *prolog[] = {
   "    pathforall ] def",
   "    currentpoint newpath moveto",
   "  } {",
-  "    8 {pop} repeat",
+  "    pop pop pop pop",
   "  } ifelse",
   "  0 pdfTextRise neg pdfTextMat dtransform rmoveto",
   "} def",
-  "/TJm { pdfFontSize 0.001 mul mul neg 0",
+  "/TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0",
   "       pdfTextMat dtransform rmoveto } def",
-  "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
+  "/TJmV { 0.001 mul pdfFontSize mul neg 0 exch",
   "        pdfTextMat dtransform rmoveto } def",
   "/Tclip { pdfTextClipPath cvx exec clip newpath",
   "         /pdfTextClipPath [] def } def",
@@ -548,19 +556,52 @@ static const char *prolog[] = {
   "  fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
   "  { currentfile pdfImBuf1 readstring pop } imagemask",
   "} def",
+  "/pdfImStr {",
+  "  2 copy exch length lt {",
+  "    2 copy get exch 1 add exch",
+  "  } {",
+  "    ()",
+  "  } ifelse",
+  "} def",
   "/pdfImM1a {",
-  "  { 2 copy get exch 1 add exch } imagemask",
+  "  { pdfImStr } imagemask",
   "  pop pop",
   "} def",
   "~23sn",
-  "% Level 2 image operators",
+  "% Level 2/3 image operators",
   "/pdfImBuf 100 string def",
-  "/pdfIm {",
-  "  image",
+  "/pdfImStr {",
+  "  2 copy exch length lt {",
+  "    2 copy get exch 1 add exch",
+  "  } {",
+  "    ()",
+  "  } ifelse",
+  "} def",
+  "/skipEOD {",
   "  { currentfile pdfImBuf readline",
   "    not { pop exit } if",
   "    (%-EOD-) eq { exit } if } loop",
   "} def",
+  "/pdfIm { image skipEOD } def",
+  "~3sn",
+  "/pdfMask {",
+  "  /ReusableStreamDecode filter",
+  "  skipEOD",
+  "  /maskStream exch def",
+  "} def",
+  "/pdfMaskEnd { maskStream closefile } def",
+  "/pdfMaskInit {",
+  "  /maskArray exch def",
+  "  /maskIdx 0 def",
+  "} def",
+  "/pdfMaskSrc {",
+  "  maskIdx maskArray length lt {",
+  "    maskArray maskIdx get",
+  "    /maskIdx maskIdx 1 add def",
+  "  } {",
+  "    ()",
+  "  } ifelse",
+  "} def",
   "~23s",
   "/pdfImSep {",
   "  findcmykcustomcolor exch",
@@ -576,17 +617,10 @@ static const char *prolog[] = {
   "      255 exch sub put",
   "    } for }",
   "  6 5 roll customcolorimage",
-  "  { currentfile pdfImBuf readline",
-  "    not { pop exit } if",
-  "    (%-EOD-) eq { exit } if } loop",
+  "  skipEOD",
   "} def",
   "~23sn",
-  "/pdfImM {",
-  "  fCol imagemask",
-  "  { currentfile pdfImBuf readline",
-  "    not { pop exit } if",
-  "    (%-EOD-) eq { exit } if } loop",
-  "} def",
+  "/pdfImM { fCol imagemask skipEOD } def",
   "~123sn",
   "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def",
   "/pdfImClip {",
@@ -892,6 +926,13 @@ struct PSOutImgClipRect {
 };
 
 //------------------------------------------------------------------------
+
+struct PSOutPaperSize {
+  PSOutPaperSize(int wA, int hA) { w = wA; h = hA; }
+  int w, h;
+};
+
+//------------------------------------------------------------------------
 // DeviceNRecoder
 //------------------------------------------------------------------------
 
@@ -944,6 +985,9 @@ DeviceNRecoder::~DeviceNRecoder() {
   if (imgStr) {
     delete imgStr;
   }
+  if (str->isEncoder()) {
+    delete str;
+  }
 }
 
 void DeviceNRecoder::reset() {
@@ -994,8 +1038,9 @@ PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *doc,
 			 int firstPage, int lastPage, PSOutMode modeA,
 			 int paperWidthA, int paperHeightA, GBool duplexA,
 			 int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
-			 GBool forceRasterizeA,
-			 GBool manualCtrlA) {
+			 GBool manualCtrlA,
+			 PSOutCustomCodeCbk customCodeCbkA,
+			 void *customCodeCbkDataA) {
   FILE *f;
   PSFileType fileTypeA;
 
@@ -1003,23 +1048,23 @@ PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *doc,
   underlayCbkData = NULL;
   overlayCbk = NULL;
   overlayCbkData = NULL;
+  customCodeCbk = customCodeCbkA;
+  customCodeCbkData = customCodeCbkDataA;
 
   fontIDs = NULL;
   fontNames = new GooHash(gTrue);
-  fontFileIDs = NULL;
-  fontFileNames = NULL;
+  t1FontNames = NULL;
   font8Info = NULL;
   font16Enc = NULL;
   imgIDs = NULL;
   formIDs = NULL;
   xobjStack = NULL;
+  paperSizes = NULL;
   embFontList = NULL;
   customColors = NULL;
   haveTextClip = gFalse;
   t3String = NULL;
 
-  forceRasterize = forceRasterizeA;
-
   // open file or pipe
   if (!strcmp(fileName, "-")) {
     fileTypeA = psStdout;
@@ -1061,29 +1106,30 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
 			 int firstPage, int lastPage, PSOutMode modeA,
 			 int paperWidthA, int paperHeightA, GBool duplexA,
 			 int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
-			 GBool forceRasterizeA,
-			 GBool manualCtrlA) {
+			 GBool manualCtrlA,
+			 PSOutCustomCodeCbk customCodeCbkA,
+			 void *customCodeCbkDataA) {
   underlayCbk = NULL;
   underlayCbkData = NULL;
   overlayCbk = NULL;
   overlayCbkData = NULL;
+  customCodeCbk = customCodeCbkA;
+  customCodeCbkData = customCodeCbkDataA;
 
   fontIDs = NULL;
   fontNames = new GooHash(gTrue);
-  fontFileIDs = NULL;
-  fontFileNames = NULL;
+  t1FontNames = NULL;
   font8Info = NULL;
   font16Enc = NULL;
   imgIDs = NULL;
   formIDs = NULL;
   xobjStack = NULL;
+  paperSizes = NULL;
   embFontList = NULL;
   customColors = NULL;
   haveTextClip = gFalse;
   t3String = NULL;
 
-  forceRasterize = forceRasterizeA;
-
   init(outputFuncA, outputStreamA, psGeneric, psTitle,
        doc, firstPage, lastPage, modeA,
        imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
@@ -1098,6 +1144,9 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
 		       GBool duplexA) {
   Catalog *catalog;
   PDFRectangle *box;
+  PSOutPaperSize *size;
+  GooList *names;
+  int pg, w, h, i;
 
   // initialize
   displayText = gTrue;
@@ -1118,14 +1167,38 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
   imgURY = imgURYA;
   if (paperWidth < 0 || paperHeight < 0) {
     Page *page;
-    if ((page = doc->getPage(firstPage))) {
-      paperWidth = (int)ceil(page->getMediaWidth());
-      paperHeight = (int)ceil(page->getMediaHeight());
-    } else {
-      error(errSyntaxError, -1, "Invalid page {0:d}", firstPage);
-      paperWidth = 1;
-      paperHeight = 1;
+    paperMatch = gTrue;
+    paperSizes = new GooList();
+    paperWidth = paperHeight = 1; // in case the document has zero pages
+    for (pg = (firstPage >= 1) ? firstPage : 1;
+	 pg <= lastPage && pg <= catalog->getNumPages();
+	 ++pg) {
+      page = catalog->getPage(pg);
+      if (page == NULL) {
+        paperMatch = gFalse;
+        break;
+      }
+      w = (int)ceil(page->getMediaWidth());
+      h = (int)ceil(page->getMediaHeight());
+      for (i = 0; i < paperSizes->getLength(); ++i) {
+	size = (PSOutPaperSize *)paperSizes->get(i);
+	if (size->w == w && size->h == h) {
+	  break;
+	}
+      }
+      if (i == paperSizes->getLength()) {
+	paperSizes->append(new PSOutPaperSize(w, h));
+      }
+      if (w > paperWidth) {
+	paperWidth = w;
+      }
+      if (h > paperHeight) {
+	paperHeight = h;
+      }
     }
+    // NB: img{LLX,LLY,URX,URY} will be set by startPage()
+  } else {
+    paperMatch = gFalse;
   }
   preload = globalParams->getPSPreload();
   if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
@@ -1161,14 +1234,18 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
   fontIDSize = 64;
   fontIDLen = 0;
   fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
-  fontFileIDSize = 64;
-  fontFileIDLen = 0;
-  fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref));
-  fontFileNameSize = 64;
-  fontFileNameLen = 0;
-  fontFileNames = (GooString **)gmallocn(fontFileNameSize, sizeof(GooString *));
-  psFileNames = (GooString **)gmallocn(fontFileNameSize, sizeof(GooString *));
-  nextTrueTypeNum = 0;
+  fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
+  for (i = 0; i < 14; ++i) {
+    fontNames->add(new GooString(psBase14SubstFonts[i].psName), 1);
+  }
+  names = globalParams->getPSResidentFonts();
+  for (i = 0; i < names->getLength(); ++i) {
+    fontNames->add((GooString *)names->get(i), 1);
+  }
+  delete names;
+  t1FontNameSize = 64;
+  t1FontNameLen = 0;
+  t1FontNames = (PST1FontName *)gmallocn(t1FontNameSize, sizeof(PST1FontName));
   font8InfoLen = 0;
   font8InfoSize = 0;
   font16EncLen = 0;
@@ -1246,6 +1323,9 @@ PSOutputDev::~PSOutputDev() {
     }
 #endif
   }
+  if (paperSizes) {
+    deleteGooList(paperSizes, PSOutPaperSize);
+  }
   if (embFontList) {
     delete embFontList;
   }
@@ -1253,14 +1333,11 @@ PSOutputDev::~PSOutputDev() {
     gfree(fontIDs);
   }
   delete fontNames;
-  if (fontFileIDs) {
-    gfree(fontFileIDs);
-  }
-  if (fontFileNames) {
-    for (i = 0; i < fontFileNameLen; ++i) {
-      delete fontFileNames[i];
+  if (t1FontNames) {
+    for (i = 0; i < t1FontNameLen; ++i) {
+      delete t1FontNames[i].psName;
     }
-    gfree(fontFileNames);
+    gfree(t1FontNames);
   }
   if (font8Info) {
     for (i = 0; i < font8InfoLen; ++i) {
@@ -1268,16 +1345,11 @@ PSOutputDev::~PSOutputDev() {
     }
     gfree(font8Info);
   }
-  if (psFileNames) {
-    for (i = 0; i < fontFileNameLen; ++i) {
-      if (psFileNames[i])
-        delete psFileNames[i];
-    }
-    gfree(psFileNames);
-  }
   if (font16Enc) {
     for (i = 0; i < font16EncLen; ++i) {
-      delete font16Enc[i].enc;
+      if (font16Enc[i].enc) {
+	delete font16Enc[i].enc;
+      }
     }
     gfree(font16Enc);
   }
@@ -1296,8 +1368,10 @@ PSOutputDev::~PSOutputDev() {
 void PSOutputDev::writeHeader(int firstPage, int lastPage,
 			      PDFRectangle *mediaBox, PDFRectangle *cropBox,
 			      int pageRotate, char *psTitle) {
-  double x1, y1, x2, y2;
   Object info, obj1;
+  PSOutPaperSize *size;
+  double x1, y1, x2, y2;
+  int i;
 
   switch (mode) {
   case psModePSOrigPageSizes:
@@ -1339,14 +1413,24 @@ void PSOutputDev::writeHeader(int firstPage, int lastPage,
     prevWidth = 0;
     prevHeight = 0;
   case psModePS:
-    writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
-	       paperWidth, paperHeight);
+    if (paperMatch) {      
+      for (i = 0; i < paperSizes->getLength(); ++i) {
+	size = (PSOutPaperSize *)paperSizes->get(i);
+	writePSFmt("%%{0:s} {1:d}x{2:d} {1:d} {2:d} 0 () ()\n",
+		   i==0 ? "DocumentMedia:" : "+", size->w, size->h);
+      }
+    } else {
+      writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
+		 paperWidth, paperHeight);
+    }
     writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight);
     writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1);
     writePS("%%EndComments\n");
-    writePS("%%BeginDefaults\n");
-    writePS("%%PageMedia: plain\n");
-    writePS("%%EndDefaults\n");
+    if (!paperMatch) {
+      writePS("%%BeginDefaults\n");
+      writePS("%%PageMedia: plain\n");
+      writePS("%%EndDefaults\n");
+    }
     break;
   case psModeEPS:
     epsX1 = cropBox->x1;
@@ -1430,7 +1514,9 @@ void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
   Page *page;
   Dict *resDict;
   Annots *annots;
-  Object obj1, obj2;
+  Object *acroForm;
+  Object obj1, obj2, obj3;
+  GooString *s;
   int pg, i;
 
   if (mode == psModeForm) {
@@ -1462,10 +1548,31 @@ void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
     }
     delete annots;
   }
+  if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) {
+    if (acroForm->dictLookup("DR", &obj1)->isDict()) {
+      setupResources(obj1.getDict());
+    }
+    obj1.free();
+    if (acroForm->dictLookup("Fields", &obj1)->isArray()) {
+      for (i = 0; i < obj1.arrayGetLength(); ++i) {
+	if (obj1.arrayGet(i, &obj2)->isDict()) {
+	  if (obj2.dictLookup("DR", &obj3)->isDict()) {
+	    setupResources(obj3.getDict());
+	  }
+	  obj3.free();
+	}
+	obj2.free();
+      }
+    }
+    obj1.free();
+  }
   if (mode != psModeForm) {
     if (mode != psModeEPS && !manualCtrl) {
-      writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n",
-		 paperWidth, paperHeight, duplexA ? "true" : "false");
+      writePSFmt("{0:s} pdfSetup\n",
+		 duplexA ? "true" : "false");
+      if (!paperMatch) {
+	writePSFmt("{0:d} {1:d} pdfSetupPaper\n", paperWidth, paperHeight);
+      }
     }
 #if OPI_SUPPORT
     if (globalParams->getPSOPI()) {
@@ -1473,6 +1580,13 @@ void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
     }
 #endif
   }
+  if (customCodeCbk) {
+    if ((s = (*customCodeCbk)(this, psOutCustomDocSetup, 0,
+			      customCodeCbkData))) {
+      writePS(s->getCString());
+      delete s;
+    }
+  }
 }
 
 void PSOutputDev::writePageTrailer() {
@@ -1627,8 +1741,6 @@ void PSOutputDev::setupFonts(Dict *resDict) {
   GfxFont *font;
   int i;
 
-  if (forceRasterize) return;
-
   gfxFontDict = NULL;
   resDict->lookupNF("Font", &obj1);
   if (obj1.isRef()) {
@@ -1891,18 +2003,10 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
   int i;
 
   // check if font is already embedded
-  for (i = 0; i < fontFileIDLen; ++i) {
-    if (fontFileIDs[i].num == id->num &&
-	fontFileIDs[i].gen == id->gen)
-      return;
-  }
-
-  // add entry to fontFileIDs list
-  if (fontFileIDLen >= fontFileIDSize) {
-    fontFileIDSize += 64;
-    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+  if (fontNames->lookupInt(psName)) {
+    return;
   }
-  fontFileIDs[fontFileIDLen++] = *id;
+  fontNames->add(psName->copy(), 1);
 
   // get the font stream and info
   refObj.initRef(id->num, id->gen);
@@ -2041,26 +2145,11 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
 void PSOutputDev::setupExternalType1Font(GooString *fileName, GooString *psName) {
   FILE *fontFile;
   int c;
-  int i;
 
-  // check if font is already embedded
-  for (i = 0; i < fontFileNameLen; ++i) {
-    if (!fontFileNames[i]->cmp(fileName)) {
-      return;
-    }
-  }
-
-  // add entry to fontFileNames list
-  if (fontFileNameLen >= fontFileNameSize) {
-    fontFileNameSize += 64;
-    fontFileNames = (GooString **)greallocn(fontFileNames,
-					  fontFileNameSize, sizeof(GooString *));
-    psFileNames = (GooString **)greallocn(psFileNames,
-				       fontFileNameSize, sizeof(GooString *));
+  if (fontNames->lookupInt(psName)) {
+    return;
   }
-  fontFileNames[fontFileNameLen] = fileName->copy();
-  psFileNames[fontFileNameLen] = psName->copy();
-  fontFileNameLen++;
+  fontNames->add(psName->copy(), 1);
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2090,18 +2179,22 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
   int i;
 
   // check if font is already embedded
-  for (i = 0; i < fontFileIDLen; ++i) {
-    if (fontFileIDs[i].num == id->num &&
-	fontFileIDs[i].gen == id->gen)
+  for (i = 0; i < t1FontNameLen; ++i) {
+    if (t1FontNames[i].fontFileID.num == id->num &&
+	t1FontNames[i].fontFileID.gen == id->gen) {
+      psName->clear();
+      psName->insert(0, t1FontNames[i].psName);
       return;
+    }
   }
-
-  // add entry to fontFileIDs list
-  if (fontFileIDLen >= fontFileIDSize) {
-    fontFileIDSize += 64;
-    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+  if (t1FontNameLen == t1FontNameSize) {
+    t1FontNameSize *= 2;
+    t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
+					    sizeof(PST1FontName));
   }
-  fontFileIDs[fontFileIDLen++] = *id;
+  t1FontNames[t1FontNameLen].fontFileID = *id;
+  t1FontNames[t1FontNameLen].psName = psName->copy();
+  ++t1FontNameLen;
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2110,13 +2203,14 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
   embFontList->append("\n");
 
   // convert it to a Type 1 font
-  fontBuf = font->readEmbFontFile(xref, &fontLen);
-  if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
-    ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
-			  outputFunc, outputStream);
-    delete ffT1C;
+  if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+    if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+      ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
+			    outputFunc, outputStream);
+      delete ffT1C;
+    }
+    gfree(fontBuf);
   }
-  gfree(fontBuf);
 
   // ending comment
   writePS("%%EndResource\n");
@@ -2130,18 +2224,22 @@ void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id,
   int i;
 
   // check if font is already embedded
-  for (i = 0; i < fontFileIDLen; ++i) {
-    if (fontFileIDs[i].num == id->num &&
-	fontFileIDs[i].gen == id->gen)
+  for (i = 0; i < t1FontNameLen; ++i) {
+    if (t1FontNames[i].fontFileID.num == id->num &&
+	t1FontNames[i].fontFileID.gen == id->gen) {
+      psName->clear();
+      psName->insert(0, t1FontNames[i].psName);
       return;
+    }
   }
-
-  // add entry to fontFileIDs list
-  if (fontFileIDLen >= fontFileIDSize) {
-    fontFileIDSize += 64;
-    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+  if (t1FontNameLen == t1FontNameSize) {
+    t1FontNameSize *= 2;
+    t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
+					    sizeof(PST1FontName));
   }
-  fontFileIDs[fontFileIDLen++] = *id;
+  t1FontNames[t1FontNameLen].fontFileID = *id;
+  t1FontNames[t1FontNameLen].psName = psName->copy();
+  ++t1FontNameLen;
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2150,15 +2248,16 @@ void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id,
   embFontList->append("\n");
 
   // convert it to a Type 1 font
-  fontBuf = font->readEmbFontFile(xref, &fontLen);
-  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-    if (ffTT->isOpenTypeCFF()) {
-      ffTT->convertToType1(psName->getCString(), NULL, gTrue,
-			   outputFunc, outputStream);
+  if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+    if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+      if (ffTT->isOpenTypeCFF()) {
+	ffTT->convertToType1(psName->getCString(), NULL, gTrue,
+			     outputFunc, outputStream);
+      }
+      delete ffTT;
     }
-    delete ffTT;
+    gfree(fontBuf);
   }
-  gfree(fontBuf);
 
   // ending comment
   writePS("%%EndResource\n");
@@ -2170,25 +2269,6 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
   int fontLen;
   FoFiTrueType *ffTT;
   int *codeToGID;
-  int i;
-
-  // check if font is already embedded
-  for (i = 0; i < fontFileIDLen; ++i) {
-    if (fontFileIDs[i].num == id->num &&
-	fontFileIDs[i].gen == id->gen) {
-      psName->appendf("_{0:d}", nextTrueTypeNum++);
-      break;
-    }
-  }
-
-  // add entry to fontFileIDs list
-  if (i == fontFileIDLen) {
-    if (fontFileIDLen >= fontFileIDSize) {
-      fontFileIDSize += 64;
-      fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-    }
-    fontFileIDs[fontFileIDLen++] = *id;
-  }
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2197,28 +2277,29 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
   embFontList->append("\n");
 
   // convert it to a Type 42 font
-  fontBuf = font->readEmbFontFile(xref, &fontLen);
-  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-    codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
-    ffTT->convertToType42(psName->getCString(),
-			  ((Gfx8BitFont *)font)->getHasEncoding()
-			    ? ((Gfx8BitFont *)font)->getEncoding()
-			    : (char **)NULL,
-			  codeToGID, outputFunc, outputStream);
-    if (codeToGID) {
-      if (font8InfoLen >= font8InfoSize) {
-	font8InfoSize += 16;
-	font8Info = (PSFont8Info *)greallocn(font8Info,
-					     font8InfoSize,
-					     sizeof(PSFont8Info));
+  if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+    if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+      codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+      ffTT->convertToType42(psName->getCString(),
+			    ((Gfx8BitFont *)font)->getHasEncoding()
+			      ? ((Gfx8BitFont *)font)->getEncoding()
+			      : (char **)NULL,
+			    codeToGID, outputFunc, outputStream);
+      if (codeToGID) {
+	if (font8InfoLen >= font8InfoSize) {
+	  font8InfoSize += 16;
+	  font8Info = (PSFont8Info *)greallocn(font8Info,
+					       font8InfoSize,
+					       sizeof(PSFont8Info));
+	}
+	font8Info[font8InfoLen].fontID = *font->getID();
+	font8Info[font8InfoLen].codeToGID = codeToGID;
+	++font8InfoLen;
       }
-      font8Info[font8InfoLen].fontID = *font->getID();
-      font8Info[font8InfoLen].codeToGID = codeToGID;
-      ++font8InfoLen;
+      delete ffTT;
     }
-    delete ffTT;
+    gfree(fontBuf);
   }
-  gfree(fontBuf);
 
   // ending comment
   writePS("%%EndResource\n");
@@ -2300,13 +2381,18 @@ void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font,
 	  codeToGIDLen = ctu->getLength();
 	  codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int));
 	  for (code = 0; code < codeToGIDLen; ++code) {
-	    if (ctu->mapToUnicode(code, &uBuf) > 0) {
+	    int n = ctu->mapToUnicode(code, &uBuf);
+	    if (n > 0) {
 	      codeToGID[code] = ffTT->mapCodeToGID(cmap, uBuf[0]);
 	    } else {
 	      codeToGID[code] = 0;
 	    }
 	  }
-	  if (globalParams->getPSLevel() >= psLevel3) {
+          if (ffTT->isOpenTypeCFF()) {
+	    ffTT->convertToCIDType0(psName->getCString(),
+				 codeToGID, codeToGIDLen,
+				 outputFunc, outputStream);
+          } else if (globalParams->getPSLevel() >= psLevel3) {
 	    // Level 3: use a CID font
 	    ffTT->convertToCIDType2(psName->getCString(),
 				    codeToGID, codeToGIDLen,
@@ -2348,18 +2434,22 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
   int i;
 
   // check if font is already embedded
-  for (i = 0; i < fontFileIDLen; ++i) {
-    if (fontFileIDs[i].num == id->num &&
-	fontFileIDs[i].gen == id->gen)
+  for (i = 0; i < t1FontNameLen; ++i) {
+    if (t1FontNames[i].fontFileID.num == id->num &&
+	t1FontNames[i].fontFileID.gen == id->gen) {
+      psName->clear();
+      psName->insert(0, t1FontNames[i].psName);
       return;
+    }
   }
-
-  // add entry to fontFileIDs list
-  if (fontFileIDLen >= fontFileIDSize) {
-    fontFileIDSize += 64;
-    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+  if (t1FontNameLen == t1FontNameSize) {
+    t1FontNameSize *= 2;
+    t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
+					    sizeof(PST1FontName));
   }
-  fontFileIDs[fontFileIDLen++] = *id;
+  t1FontNames[t1FontNameLen].fontFileID = *id;
+  t1FontNames[t1FontNameLen].psName = psName->copy();
+  ++t1FontNameLen;
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2368,20 +2458,21 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
   embFontList->append("\n");
 
   // convert it to a Type 0 font
-  fontBuf = font->readEmbFontFile(xref, &fontLen);
-  if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
-    if (globalParams->getPSLevel() >= psLevel3) {
-      // Level 3: use a CID font
-      ffT1C->convertToCIDType0(psName->getCString(), NULL, 0,
-                               outputFunc, outputStream);
-    } else {
-      // otherwise: use a non-CID composite font
-      ffT1C->convertToType0(psName->getCString(), NULL, 0,
-                            outputFunc, outputStream);
+  if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+    if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+      if (globalParams->getPSLevel() >= psLevel3) {
+	// Level 3: use a CID font
+	ffT1C->convertToCIDType0(psName->getCString(), NULL, 0,
+				 outputFunc, outputStream);
+      } else {
+	// otherwise: use a non-CID composite font
+	ffT1C->convertToType0(psName->getCString(), NULL, 0,
+			      outputFunc, outputStream);
+      }
+      delete ffT1C;
     }
-    delete ffT1C;
+    gfree(fontBuf);
   }
-  gfree(fontBuf);
 
   // ending comment
   writePS("%%EndResource\n");
@@ -2393,23 +2484,6 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
   char *fontBuf;
   int fontLen;
   FoFiTrueType *ffTT;
-  int i;
-
-  // check if font is already embedded
-  for (i = 0; i < fontFileIDLen; ++i) {
-    if (fontFileIDs[i].num == id->num &&
-	fontFileIDs[i].gen == id->gen) {
-      psName->appendf("_{0:d}", nextTrueTypeNum++);
-      break;
-    }
-  }
-
-  // add entry to fontFileIDs list
-  if (fontFileIDLen >= fontFileIDSize) {
-    fontFileIDSize += 64;
-    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
-  }
-  fontFileIDs[fontFileIDLen++] = *id;
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2418,26 +2492,27 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
   embFontList->append("\n");
 
   // convert it to a Type 0 font
-  fontBuf = font->readEmbFontFile(xref, &fontLen);
-  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-    if (globalParams->getPSLevel() >= psLevel3) {
-      // Level 3: use a CID font
-      ffTT->convertToCIDType2(psName->getCString(),
-			      ((GfxCIDFont *)font)->getCIDToGID(),
-			      ((GfxCIDFont *)font)->getCIDToGIDLen(),
-			      needVerticalMetrics,
-			      outputFunc, outputStream);
-    } else {
-      // otherwise: use a non-CID composite font
-      ffTT->convertToType0(psName->getCString(),
-			   ((GfxCIDFont *)font)->getCIDToGID(),
-			   ((GfxCIDFont *)font)->getCIDToGIDLen(),
-			   needVerticalMetrics,
-			   outputFunc, outputStream);
+  if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+    if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+      if (globalParams->getPSLevel() >= psLevel3) {
+	// Level 3: use a CID font
+	ffTT->convertToCIDType2(psName->getCString(),
+				((GfxCIDFont *)font)->getCIDToGID(),
+				((GfxCIDFont *)font)->getCIDToGIDLen(),
+				needVerticalMetrics,
+				outputFunc, outputStream);
+      } else {
+	// otherwise: use a non-CID composite font
+	ffTT->convertToType0(psName->getCString(),
+			     ((GfxCIDFont *)font)->getCIDToGID(),
+			     ((GfxCIDFont *)font)->getCIDToGIDLen(),
+			     needVerticalMetrics,
+			     outputFunc, outputStream);
+      }
+      delete ffTT;
     }
-    delete ffTT;
+    gfree(fontBuf);
   }
-  gfree(fontBuf);
 
   // ending comment
   writePS("%%EndResource\n");
@@ -2451,18 +2526,22 @@ void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id,
   int i;
 
   // check if font is already embedded
-  for (i = 0; i < fontFileIDLen; ++i) {
-    if (fontFileIDs[i].num == id->num &&
-	fontFileIDs[i].gen == id->gen)
+  for (i = 0; i < t1FontNameLen; ++i) {
+    if (t1FontNames[i].fontFileID.num == id->num &&
+	t1FontNames[i].fontFileID.gen == id->gen) {
+      psName->clear();
+      psName->insert(0, t1FontNames[i].psName);
       return;
+    }
   }
-
-  // add entry to fontFileIDs list
-  if (fontFileIDLen >= fontFileIDSize) {
-    fontFileIDSize += 64;
-    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+  if (t1FontNameLen == t1FontNameSize) {
+    t1FontNameSize *= 2;
+    t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize,
+					    sizeof(PST1FontName));
   }
-  fontFileIDs[fontFileIDLen++] = *id;
+  t1FontNames[t1FontNameLen].fontFileID = *id;
+  t1FontNames[t1FontNameLen].psName = psName->copy();
+  ++t1FontNameLen;
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2471,26 +2550,27 @@ void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id,
   embFontList->append("\n");
 
   // convert it to a Type 0 font
-  fontBuf = font->readEmbFontFile(xref, &fontLen);
-  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
-    if (ffTT->isOpenTypeCFF()) {
-      if (globalParams->getPSLevel() >= psLevel3) {
-	// Level 3: use a CID font
-	ffTT->convertToCIDType0(psName->getCString(),
-                                ((GfxCIDFont *)font)->getCIDToGID(),
-                                ((GfxCIDFont *)font)->getCIDToGIDLen(),
-				outputFunc, outputStream);
-      } else {
-	// otherwise: use a non-CID composite font
-	ffTT->convertToType0(psName->getCString(),
-                             ((GfxCIDFont *)font)->getCIDToGID(),
-                             ((GfxCIDFont *)font)->getCIDToGIDLen(),
-                             outputFunc, outputStream);
+  if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
+    if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+      if (ffTT->isOpenTypeCFF()) {
+	if (globalParams->getPSLevel() >= psLevel3) {
+	  // Level 3: use a CID font
+	  ffTT->convertToCIDType0(psName->getCString(),
+				  ((GfxCIDFont *)font)->getCIDToGID(),
+				  ((GfxCIDFont *)font)->getCIDToGIDLen(),
+				  outputFunc, outputStream);
+	} else {
+	  // otherwise: use a non-CID composite font
+	  ffTT->convertToType0(psName->getCString(),
+			       ((GfxCIDFont *)font)->getCIDToGID(),
+			       ((GfxCIDFont *)font)->getCIDToGIDLen(),
+			       outputFunc, outputStream);
+	}
       }
+      delete ffTT;
     }
-    delete ffTT;
+    gfree(fontBuf);
   }
-  gfree(fontBuf);
 
   // ending comment
   writePS("%%EndResource\n");
@@ -2552,6 +2632,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName,
     gfx = new Gfx(doc, this, resDict, &box, NULL);
     inType3Char = gTrue;
     for (i = 0; i < charProcs->getLength(); ++i) {
+      t3FillColorOnly = gFalse;
       t3Cacheable = gFalse;
       t3NeedsRestore = gFalse;
       writePS("/");
@@ -2625,8 +2706,9 @@ GooString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) {
 }
 
 void PSOutputDev::setupImages(Dict *resDict) {
-  Object xObjDict, xObj, xObjRef, subtypeObj;
-  int i;
+  Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef;
+  Ref imgID;
+  int i, j;
 
   if (!(mode == psModeForm || inType3Char || preload)) {
     return;
@@ -2642,7 +2724,29 @@ void PSOutputDev::setupImages(Dict *resDict) {
 	xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
 	if (subtypeObj.isName("Image")) {
 	  if (xObjRef.isRef()) {
-	    setupImage(xObjRef.getRef(), xObj.getStream());
+	    imgID = xObjRef.getRef();
+	    for (j = 0; j < imgIDLen; ++j) {
+	      if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) {
+		break;
+	      }
+	    }
+	    if (j == imgIDLen) {
+	      if (imgIDLen >= imgIDSize) {
+		if (imgIDSize == 0) {
+		  imgIDSize = 64;
+		} else {
+		  imgIDSize *= 2;
+		}
+		imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
+	      }
+	      imgIDs[imgIDLen++] = imgID;
+	      setupImage(imgID, xObj.getStream(), gFalse);
+	      if (level >= psLevel3 &&
+		  xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) {
+		setupImage(imgID, maskObj.getStream(), gTrue);
+	      }
+	      maskObj.free();
+	    }
 	  } else {
 	    error(errSyntaxError, -1,
 		  "Image in resource dict is not an indirect reference");
@@ -2657,31 +2761,13 @@ void PSOutputDev::setupImages(Dict *resDict) {
   xObjDict.free();
 }
 
-void PSOutputDev::setupImage(Ref id, Stream *str) {
+void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
   GBool useRLE, useCompressed, useASCIIHex;
   GooString *s;
   int c;
   int size, line, col, i;
   int outerSize, outer;
 
-  // check if image is already setup
-  for (i = 0; i < imgIDLen; ++i) {
-    if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) {
-      return;
-    }
-  }
-
-  // add entry to imgIDs list
-  if (imgIDLen >= imgIDSize) {
-    if (imgIDSize == 0) {
-      imgIDSize = 64;
-    } else {
-      imgIDSize *= 2;
-    }
-    imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
-  }
-  imgIDs[imgIDLen++] = id;
-
   // filters
   //~ this does not correctly handle the DeviceN color space
   //~   -- need to use DeviceNRecoder
@@ -2690,17 +2776,21 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
     useCompressed = gFalse;
     useASCIIHex = gTrue;
   } else {
-    s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
-    if (s) {
+    if (globalParams->getPSUncompressPreloadedImages()) {
       useRLE = gFalse;
-      useCompressed = gTrue;
-      delete s;
-    } else {
-      useRLE = gTrue;
       useCompressed = gFalse;
+    } else {
+      s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
+      if (s) {
+	useRLE = gFalse;
+	useCompressed = gTrue;
+	delete s;
+      } else {
+	useRLE = gTrue;
+	useCompressed = gFalse;
+      }
     }
-    useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
-                  globalParams->getPSASCIIHex();
+    useASCIIHex = globalParams->getPSASCIIHex();
   }
   if (useCompressed) {
     str = str->getUndecodedStream();
@@ -2754,8 +2844,8 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
   }
   outerSize = size/65535 + 1;
 
-  writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n",
-	     outerSize, id.num, id.gen);
+  writePSFmt("{0:d} array dup /{1:s}Data_{2:d}_{3:d} exch def\n",
+	     size, mask ? "Mask" : "Im", id.num, id.gen);
   str->close();
 
   // write the data into the array
@@ -2945,9 +3035,11 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
 				  GBool printing,
 				  GBool (*abortCheckCbk)(void *data),
 				  void *abortCheckCbkData) {
-#if HAVE_SPLASH
   PreScanOutputDev *scan;
   GBool rasterize;
+#if HAVE_SPLASH
+  GBool mono;
+  double dpi;
   SplashOutputDev *splashOut;
   SplashColor paperColor;
   PDFRectangle box;
@@ -2957,422 +3049,233 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
   Object obj;
   Guchar *p;
   Guchar col[4];
+  double hDPI2, vDPI2;
   double m0, m1, m2, m3, m4, m5;
+  int nStripes, stripeH, stripeY;
   int c, w, h, x, y, comp, i;
-  double splashDPI;
-  char hexBuf[32*2 + 2];	// 32 values X 2 chars/value + line ending + null
-  Guchar digit;
-  GBool useBinary;
-  GBool isGray;
-  int compCyan;
+#endif
 
-  if (!forceRasterize) {
+  if (globalParams->getPSAlwaysRasterize()) {
+    rasterize = gTrue;
+  } else {
     scan = new PreScanOutputDev(doc);
     page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
-                     sliceX, sliceY, sliceW, sliceH,
-                     printing, abortCheckCbk, abortCheckCbkData);
-    rasterize = scan->usesTransparency() || scan->hasLevel1PSBug();
+		       sliceX, sliceY, sliceW, sliceH,
+		       printing, abortCheckCbk, abortCheckCbkData);
+    rasterize = scan->usesTransparency() || scan->usesPatternImageMask();
     delete scan;
-  } else {
-    rasterize = gTrue;
   }
   if (!rasterize) {
     return gTrue;
   }
 
-  // rasterize the page
-  if (level == psLevel1) {
+#if HAVE_SPLASH
+  // get the rasterization parameters
+  dpi = globalParams->getPSRasterResolution();
+  mono = globalParams->getPSRasterMono();
+
+  // start the PS page
+  page->makeBox(dpi, dpi, rotateA, useMediaBox, gFalse,
+		sliceX, sliceY, sliceW, sliceH, &box, &crop);
+  rotateA += page->getRotate();
+  if (rotateA >= 360) {
+    rotateA -= 360;
+  } else if (rotateA < 0) {
+    rotateA += 360;
+  }
+  state = new GfxState(dpi, dpi, &box, rotateA, gFalse);
+  startPage(page->getNum(), state);
+  delete state;
+
+  // set up the SplashOutputDev
+  if (mono || level == psLevel1) {
     paperColor[0] = 0xff;
     splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
-				    paperColor, gTrue, gFalse);
+				    paperColor, gFalse,
+				    globalParams->getAntialiasPrinting());
 #if SPLASH_CMYK
-  } else if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
+  } else if (level == psLevel1Sep) {
     paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
     splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
-				    paperColor, gTrue, gFalse);
-#else
-  } else if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
-    error(errInternal, -1, "pdftops was built without CMYK support, levelnsep needs it to work in this file");
-    return gFalse;
+				    paperColor, gFalse,
+				    globalParams->getAntialiasPrinting());
 #endif
   } else {
     paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
     splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
-				    paperColor, gTrue, gFalse);
+				    paperColor, gFalse,
+				    globalParams->getAntialiasPrinting());
   }
   splashOut->startDoc(doc);
-  splashDPI = globalParams->getSplashResolution();
-  if (splashDPI < 1.0) {
-    splashDPI = defaultSplashDPI;
-  }
-  page->displaySlice(splashOut, splashDPI, splashDPI, rotateA,
-		     useMediaBox, crop,
-		     sliceX, sliceY, sliceW, sliceH,
-		     printing, abortCheckCbk, abortCheckCbkData);
 
-  // start the PS page
-  page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse,
-		sliceX, sliceY, sliceW, sliceH, &box, &crop);
-  rotateA += page->getRotate();
-  if (rotateA >= 360) {
-    rotateA -= 360;
-  } else if (rotateA < 0) {
-    rotateA += 360;
+  // break the page into stripes
+  hDPI2 = xScale * dpi;
+  vDPI2 = yScale * dpi;
+  if (sliceW < 0 || sliceH < 0) {
+    if (useMediaBox) {
+      box = *page->getMediaBox();
+    } else {
+      box = *page->getCropBox();
+    }
+    sliceX = sliceY = 0;
+    sliceW = (int)((box.x2 - box.x1) * hDPI2 / 72.0);
+    sliceH = (int)((box.y2 - box.y1) * vDPI2 / 72.0);
   }
-  state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse);
-  startPage(page->getNum(), state);
-  delete state;
-  switch (rotateA) {
-  case 0:
-  default:  // this should never happen
+  nStripes = (int)ceil((double)(sliceW * sliceH) /
+		       (double)rasterizationSliceSize);
+  stripeH = (sliceH + nStripes - 1) / nStripes;
+
+  // render the stripes
+  for (stripeY = sliceY; stripeY < sliceH; stripeY += stripeH) {
+
+    // rasterize a stripe
+    page->makeBox(hDPI2, vDPI2, 0, useMediaBox, gFalse,
+		  sliceX, stripeY, sliceW, stripeH, &box, &crop);
     m0 = box.x2 - box.x1;
     m1 = 0;
     m2 = 0;
     m3 = box.y2 - box.y1;
     m4 = box.x1;
     m5 = box.y1;
-    break;
-  case 90:
-    m0 = 0;
-    m1 = box.y2 - box.y1;
-    m2 = -(box.x2 - box.x1);
-    m3 = 0;
-    m4 = box.x2;
-    m5 = box.y1;
-    break;
-  case 180:
-    m0 = -(box.x2 - box.x1);
-    m1 = 0;
-    m2 = 0;
-    m3 = -(box.y2 - box.y1);
-    m4 = box.x2;
-    m5 = box.y2;
-    break;
-  case 270:
-    m0 = 0;
-    m1 = -(box.y2 - box.y1);
-    m2 = box.x2 - box.x1;
-    m3 = 0;
-    m4 = box.x1;
-    m5 = box.y2;
-    break;
-  }
-
-  //~ need to add the process colors
-
-  // draw the rasterized image
-  bitmap = splashOut->getBitmap();
-  w = bitmap->getWidth();
-  h = bitmap->getHeight();
-  writePS("gsave\n");
-  writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
-	     m0, m1, m2, m3, m4, m5);
-  switch (level) {
-  case psLevel1:
-    useBinary = globalParams->getPSBinary();
-    writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1{5:s}\n",
-	       w, h, w, -h, h,
-	       useBinary ? "Bin" : "");
-    p = bitmap->getDataPtr();
-    i = 0;
-    if (useBinary) {
+    page->displaySlice(splashOut, hDPI2, vDPI2,
+		       (360 - page->getRotate()) % 360, useMediaBox, crop,
+		       sliceX, stripeY, sliceW, stripeH,
+		       printing, abortCheckCbk, abortCheckCbkData);
+
+    // draw the rasterized image
+    bitmap = splashOut->getBitmap();
+    w = bitmap->getWidth();
+    h = bitmap->getHeight();
+    writePS("gsave\n");
+    writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
+	       m0, m1, m2, m3, m4, m5);
+    switch (level) {
+    case psLevel1:
+      writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
+		 w, h, w, -h, h);
+      p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
+      i = 0;
       for (y = 0; y < h; ++y) {
-        for (x = 0; x < w; ++x) {
-	  hexBuf[i++] = *p++;
-	  if (i >= 64) {
-	    writePSBuf(hexBuf, i);
+	for (x = 0; x < w; ++x) {
+	  writePSFmt("{0:02x}", *p++);
+	  if (++i == 32) {
+	    writePSChar('\n');
 	    i = 0;
 	  }
 	}
       }
-    } else {
+      if (i != 0) {
+	writePSChar('\n');
+      }
+      break;
+    case psLevel1Sep:
+      writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
+		 w, h, w, -h, h);
+      p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
+      i = 0;
+      col[0] = col[1] = col[2] = col[3] = 0;
       for (y = 0; y < h; ++y) {
-        for (x = 0; x < w; ++x) {
-	  digit = *p / 16;
-	  hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
-	  digit = *p++ % 16;
-	  hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
-	  if (i >= 64) {
-	    hexBuf[i++] = '\n';
-	    writePSBuf(hexBuf, i);
-	    i = 0;
+	for (comp = 0; comp < 4; ++comp) {
+	  for (x = 0; x < w; ++x) {
+	    writePSFmt("{0:02x}", p[4*x + comp]);
+	    col[comp] |= p[4*x + comp];
+	    if (++i == 32) {
+	      writePSChar('\n');
+	      i = 0;
+	    }
 	  }
 	}
+	p -= bitmap->getRowSize();
       }
-    }
-    if (i != 0) {
-      if (!useBinary) {
-	hexBuf[i++] = '\n';
+      if (i != 0) {
+	writePSChar('\n');
       }
-      writePSBuf(hexBuf, i);
-    }
-    break;
-  case psLevel1Sep:
-    useBinary = globalParams->getPSBinary();
-    p = bitmap->getDataPtr();
-    isGray = gTrue;
-    for (y = 0; y < h; ++y) {
-      for (x = 0; x < w; ++x) {
-	if (p[4*x] != p[4*x + 1] || p[4*x] != p[4*x + 2]) {
-	  isGray = gFalse;
-	  y = h;
-	  break;
-	}
+      if (col[0]) {
+	processColors |= psProcessCyan;
       }
-      p += bitmap->getRowSize();
-    }
-    writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1{5:s}{6:s}\n",
-	       w, h, w, -h, h,
-	       isGray ? "" : "Sep",
-	       useBinary ? "Bin" : "");
-    p = bitmap->getDataPtr();
-    i = 0;
-    col[0] = col[1] = col[2] = col[3] = 0;
-    if (isGray) {
-      int g;
-      if ((psProcessBlack & processColors) == 0) {
-	for (y = 0; y < h; ++y) {
-	  for (x = 0; x < w; ++x) {
-	    if (p[4*x] > 0 || p[4*x + 3] > 0) {
-	      col[3] = 1;
-	      y = h;
-	      break;
-	    }
-	  }
-          p += bitmap->getRowSize();
-	}
-        p = bitmap->getDataPtr();
+      if (col[1]) {
+	processColors |= psProcessMagenta;
       }
-      for (y = 0; y < h; ++y) {
-	if (useBinary) {
-	  for (x = 0; x < w; ++x) {
-	    g = p[4*x] + p[4*x + 3];
-	    g = 255 - g;
-	    if (g < 0) g = 0;
-	    hexBuf[i++] = (Guchar) g;
-	    if (i >= 64) {
-	      writePSBuf(hexBuf, i);
-	      i = 0;
-	    }
-	  }
-	} else {
-	  for (x = 0; x < w; ++x) {
-	    g = p[4*x] + p[4*x + 3];
-	    g = 255 - g;
-	    if (g < 0) g = 0;
-	    digit = g / 16;
-	    hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
-	    digit = g % 16;
-	    hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
-	    if (i >= 64) {
-	      hexBuf[i++] = '\n';
-	      writePSBuf(hexBuf, i);
-	      i = 0;
-	    }
-	  }
-        }
-        p += bitmap->getRowSize();
+      if (col[2]) {
+	processColors |= psProcessYellow;
       }
-    } else if (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0) {
-      for (y = 0; y < h; ++y) {
-        for (comp = 0; comp < 4; ++comp) {
-	  if (useBinary) {
-	    for (x = 0; x < w; ++x) {
-	      col[comp] |= p[4*x + comp];
-	      hexBuf[i++] = p[4*x + comp];
-	      if (i >= 64) {
-	        writePSBuf(hexBuf, i);
-	        i = 0;
-	      }
-	    }
-	  } else {
-	    for (x = 0; x < w; ++x) {
-	      col[comp] |= p[4*x + comp];
-	      digit = p[4*x + comp] / 16;
-	      hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
-	      digit = p[4*x + comp] % 16;
-	      hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
-	      if (i >= 64) {
-	        hexBuf[i++] = '\n';
-	        writePSBuf(hexBuf, i);
-	        i = 0;
-	      }
-	    }
-	  }
-        }
-        p += bitmap->getRowSize();
+      if (col[3]) {
+	processColors |= psProcessBlack;
       }
-    } else {
-      for (y = 0; y < h; ++y) {
-        for (comp = 0; comp < 4; ++comp) {
-	  if (useBinary) {
-	    for (x = 0; x < w; ++x) {
-	      hexBuf[i++] = p[4*x + comp];
-	      if (i >= 64) {
-	        writePSBuf(hexBuf, i);
-	        i = 0;
-	      }
-	    }
-	  } else {
-	    for (x = 0; x < w; ++x) {
-	      digit = p[4*x + comp] / 16;
-	      hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
-	      digit = p[4*x + comp] % 16;
-	      hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
-	      if (i >= 64) {
-	        hexBuf[i++] = '\n';
-	        writePSBuf(hexBuf, i);
-	        i = 0;
-	      }
-	    }
-	  }
-        }
-        p += bitmap->getRowSize();
+      break;
+    case psLevel2:
+    case psLevel2Sep:
+    case psLevel3:
+    case psLevel3Sep:
+      if (mono) {
+	writePS("/DeviceGray setcolorspace\n");
+      } else {
+	writePS("/DeviceRGB setcolorspace\n");
       }
-    }
-    if (i != 0) {
-      if (!useBinary) {
-        hexBuf[i++] = '\n';
+      writePS("<<\n  /ImageType 1\n");
+      writePSFmt("  /Width {0:d}\n", bitmap->getWidth());
+      writePSFmt("  /Height {0:d}\n", bitmap->getHeight());
+      writePSFmt("  /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
+      writePS("  /BitsPerComponent 8\n");
+      if (mono) {
+	writePS("  /Decode [0 1]\n");
+      } else {
+	writePS("  /Decode [0 1 0 1 0 1]\n");
       }
-      writePSBuf(hexBuf, i);
-    }
-    if (col[0]) {
-      processColors |= psProcessCyan;
-    }
-    if (col[1]) {
-      processColors |= psProcessMagenta;
-    }
-    if (col[2]) {
-      processColors |= psProcessYellow;
-    }
-    if (col[3]) {
-      processColors |= psProcessBlack;
-    }
-    break;
-  case psLevel2Sep:
-  case psLevel3Sep:
-    obj.initNull();
-    str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 4, &obj);
-    isGray = gTrue;
-    while ((compCyan = str0->getChar()) != EOF) {
-      if (str0->getChar() != compCyan ||
-          str0->getChar() != compCyan) {
-	isGray = gFalse;
-	break;
+      writePS("  /DataSource currentfile\n");
+      if (globalParams->getPSASCIIHex()) {
+	writePS("    /ASCIIHexDecode filter\n");
+      } else {
+	writePS("    /ASCII85Decode filter\n");
       }
-      str0->getChar();
-    }
-    str0->reset();
-    if (isGray) {
-      writePS("/DeviceGray setcolorspace\n");
-      str = new RunLengthEncoder(new CMKYGrayEncoder(str0));
-    } else {
-      processColors |= psProcessCMYK;
-      writePS("/DeviceCMYK setcolorspace\n");
+      writePS("    /RunLengthDecode filter\n");
+      writePS(">>\n");
+      writePS("image\n");
+      obj.initNull();
+      p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize();
+      str0 = new MemStream((char *)p, 0, w * h * (mono ? 1 : 3), &obj);
       str = new RunLengthEncoder(str0);
-    }
-    writePS("<<\n  /ImageType 1\n");
-    writePSFmt("  /Width {0:d}\n", bitmap->getWidth());
-    writePSFmt("  /Height {0:d}\n", bitmap->getHeight());
-    writePSFmt("  /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
-    writePS("  /BitsPerComponent 8\n");
-    if (isGray) {
-      writePS("  /Decode [1 0]\n");
-    } else {
-      writePS("  /Decode [0 1 0 1 0 1 0 1]\n");
-    }
-    writePS("  /DataSource currentfile\n");
-    useBinary = globalParams->getPSBinary();
-    if (useBinary) {
-      /* nothing to do */;
-    } else if (globalParams->getPSASCIIHex()) {
-      writePS("    /ASCIIHexDecode filter\n");
-    } else {
-      writePS("    /ASCII85Decode filter\n");
-    }
-    writePS("    /RunLengthDecode filter\n");
-    writePS(">>\n");
-    if (useBinary) {
-      /* nothing to do */;
-    } else if (globalParams->getPSASCIIHex()) {
-      str = new ASCIIHexEncoder(str);
-    } else {
-      str = new ASCII85Encoder(str);
-    }
-    str->reset();
-    if (useBinary) {
-      int len = 0;
-      while (str->getChar() != EOF) {
-	len++;
+      if (globalParams->getPSASCIIHex()) {
+	str = new ASCIIHexEncoder(str);
+      } else {
+	str = new ASCII85Encoder(str);
       }
       str->reset();
-      writePSFmt("%%BeginData: {0:d} Binary Bytes\n", len+6+1);
-    }
-    writePS("image\n");
-    while ((c = str->getChar()) != EOF) {
-      writePSChar(c);
-    }
-    if (useBinary) {
-      writePS("\n%%EndData\n");
-    } else if (isGray) {
+      while ((c = str->getChar()) != EOF) {
+	writePSChar(c);
+      }
+      str->close();
+      delete str;
+      delete str0;
       writePSChar('\n');
+      processColors |= mono ? psProcessBlack : psProcessCMYK;
+      break;
     }
-    str->close();
-    delete str;
-    delete str0;
-    break;
-  case psLevel2:
-  case psLevel3:
-    writePS("/DeviceRGB setcolorspace\n");
-    writePS("<<\n  /ImageType 1\n");
-    writePSFmt("  /Width {0:d}\n", bitmap->getWidth());
-    writePSFmt("  /Height {0:d}\n", bitmap->getHeight());
-    writePSFmt("  /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
-    writePS("  /BitsPerComponent 8\n");
-    writePS("  /Decode [0 1 0 1 0 1]\n");
-    writePS("  /DataSource currentfile\n");
-    if (globalParams->getPSASCIIHex()) {
-      writePS("    /ASCIIHexDecode filter\n");
-    } else {
-      writePS("    /ASCII85Decode filter\n");
-    }
-    writePS("    /RunLengthDecode filter\n");
-    writePS(">>\n");
-    writePS("image\n");
-    obj.initNull();
-    str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj);
-    str = new RunLengthEncoder(str0);
-    if (globalParams->getPSASCIIHex()) {
-      str = new ASCIIHexEncoder(str);
-    } else {
-      str = new ASCII85Encoder(str);
-    }
-    str->reset();
-    while ((c = str->getChar()) != EOF) {
-      writePSChar(c);
-    }
-    str->close();
-    delete str;
-    delete str0;
-    processColors |= psProcessCMYK;
-    break;
+    writePS("grestore\n");
   }
+
   delete splashOut;
-  writePS("grestore\n");
 
   // finish the PS page
   endPage();
 
   return gFalse;
-#else
+
+#else // HAVE_SPLASH
+
+  error(errSyntaxWarning, -1,
+	"PDF page uses transparency and PSOutputDev was built without"
+	" the Splash rasterizer - output may not be correct");
   return gTrue;
-#endif
+#endif // HAVE_SPLASH
 }
 
 void PSOutputDev::startPage(int pageNum, GfxState *state) {
-  int x1, y1, x2, y2, width, height;
+  Page *page;
+  int x1, y1, x2, y2, width, height, t;
   int imgWidth, imgHeight, imgWidth2, imgHeight2;
   GBool landscape;
+  GooString *s;
 
 
   if (mode == psModePS || mode == psModePSOrigPageSizes) {
@@ -3391,6 +3294,19 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
     } else {
       writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
     }
+    if (paperMatch) {
+      page = doc->getCatalog()->getPage(pageNum);
+      imgLLX = imgLLY = 0;
+      imgURX = (int)ceil(page->getMediaWidth());
+      imgURY = (int)ceil(page->getMediaHeight());
+      if (state->getRotate() == 90 || state->getRotate() == 270) {
+	t = imgURX;
+	imgURX = imgURY;
+	imgURY = t;
+      }
+      writePSFmt("%%PageMedia: {0:d}x{1:d}\n", imgURX, imgURY);
+      writePSFmt("%%PageBoundingBox: 0 0 {0:d} {1:d}\n", imgURX, imgURY);
+    }
     if (mode != psModePSOrigPageSizes)
       writePS("%%BeginPageSetup\n");
   }
@@ -3446,20 +3362,25 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
     height = y2 - y1;
     tx = ty = 0;
     // rotation and portrait/landscape mode
-    if (rotate0 >= 0) {
+    if (paperMatch) {
+      rotate = (360 - state->getRotate()) % 360;
+      landscape = gFalse;
+    } else if (rotate0 >= 0) {
       rotate = (360 - rotate0) % 360;
       landscape = gFalse;
     } else {
       rotate = (360 - state->getRotate()) % 360;
       if (rotate == 0 || rotate == 180) {
-	if (width > height && width > imgWidth) {
+	if ((width < height && imgWidth > imgHeight && height > imgHeight) ||
+	    (width > height && imgWidth < imgHeight && width > imgWidth)) {
 	  rotate += 90;
 	  landscape = gTrue;
 	} else {
 	  landscape = gFalse;
 	}
       } else { // rotate == 90 || rotate == 270
-	if (height > width && height > imgWidth) {
+	if ((height < width && imgWidth > imgHeight && width > imgHeight) ||
+	    (height > width && imgWidth < imgHeight && height > imgWidth)) {
 	  rotate = 270 - rotate;
 	  landscape = gTrue;
 	} else {
@@ -3469,6 +3390,9 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
     }
     writePSFmt("%%PageOrientation: {0:s}\n",
 	       landscape ? "Landscape" : "Portrait");
+    if (paperMatch) {
+      writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY);
+    }
     writePS("pdfStartPage\n");
     if (rotate == 0) {
       imgWidth2 = imgWidth;
@@ -3518,8 +3442,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
     }
     // center
     if (tx0 >= 0 && ty0 >= 0) {
-      tx += rotate == 0 ? tx0 : ty0;
-      ty += rotate == 0 ? ty0 : -tx0;
+      tx += (rotate == 0 || rotate == 180) ? tx0 : ty0;
+      ty += (rotate == 0 || rotate == 180) ? ty0 : -tx0;
     } else if (globalParams->getPSCenter()) {
       if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
 	tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2;
@@ -3529,8 +3453,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
 	ty += (imgHeight2 - yScale * height) / 2;
       }
     }
-    tx += rotate == 0 ? imgLLX : imgLLY;
-    ty += rotate == 0 ? imgLLY : -imgLLX;
+    tx += (rotate == 0 || rotate == 180) ? imgLLX : imgLLY;
+    ty += (rotate == 0 || rotate == 180) ? imgLLY : -imgLLX;
     if (tx != 0 || ty != 0) {
       writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
     }
@@ -3544,7 +3468,6 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
       writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
     }
 
-    writePS("%%EndPageSetup\n");
     ++seqPage;
     break;
 
@@ -3581,6 +3504,18 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
     rotate = 0;
     break;
   }
+
+  if (customCodeCbk) {
+    if ((s = (*customCodeCbk)(this, psOutCustomPageSetup, pageNum,
+			      customCodeCbkData))) {
+      writePS(s->getCString());
+      delete s;
+    }
+  }
+
+  if (mode == psModePS) {
+    writePS("%%EndPageSetup\n");
+  }
 }
 
 void PSOutputDev::endPage() {
@@ -3963,7 +3898,7 @@ void PSOutputDev::restoreTextPos(GfxState *state) {
 
 void PSOutputDev::stroke(GfxState *state) {
   doPath(state->getPath());
-  if (t3String) {
+  if (inType3Char && t3FillColorOnly) {
     // if we're construct a cacheable Type 3 glyph, we need to do
     // everything in the fill color
     writePS("Sf\n");
@@ -4019,6 +3954,7 @@ GBool PSOutputDev::tilingPatternFillL1(GfxState *state, Catalog *cat, Object *st
   if (paintType == 2) {
     writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n",
 	       xStep, bbox[0], bbox[1], bbox[2], bbox[3]);
+    t3FillColorOnly = gTrue;
   } else
   {
     if (x1 - 1 <= x0) {
@@ -4026,6 +3962,7 @@ GBool PSOutputDev::tilingPatternFillL1(GfxState *state, Catalog *cat, Object *st
     } else {
       writePSFmt("{0:.6g} 0 setcharwidth\n", xStep);
     }
+    t3FillColorOnly = gFalse;
   }
   inType3Char = gTrue;
   ++numTilingPatterns;
@@ -4040,6 +3977,7 @@ GBool PSOutputDev::tilingPatternFillL1(GfxState *state, Catalog *cat, Object *st
 
   // draw the tiles
   writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns);
+  writePS("fCol\n");
   writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
 	     mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
   writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
@@ -4240,7 +4178,10 @@ GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading,
   double xMin, yMin, xMax, yMax;
   double x0, y0, r0, x1, y1, r1, t0, t1;
   double xa, ya, ra;
-  double sz, xz, yz, sMin, sMax, sa, ta;
+  double sz, sMin, sMax, h, ta;
+  double sLeft, sRight, sTop, sBottom, sZero, sDiag;
+  GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero;
+  GBool haveSMin, haveSMax;
   double theta, alpha, a1, a2;
   GBool enclosed;
   int i;
@@ -4259,19 +4200,25 @@ GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading,
 
   // Compute the point at which r(s) = 0; check for the enclosed
   // circles case; and compute the angles for the tangent lines.
-  if (r0 == r1) {
-    enclosed = x0 == x1 && y0 == y1;
+  // Compute the point at which r(s) = 0; check for the enclosed
+  // circles case; and compute the angles for the tangent lines.
+  h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
+  if (h == 0) {
+    enclosed = gTrue;
+    theta = 0; // make gcc happy
+    sz = 0; // make gcc happy
+  } else if (r1 - r0 == 0) {
+    enclosed = gFalse;
     theta = 0;
     sz = 0; // make gcc happy
+  } else if (fabs(r1 - r0) >= h) {
+    enclosed = gTrue;
+    theta = 0; // make gcc happy
+    sz = 0; // make gcc happy
   } else {
+    enclosed = gFalse;
     sz = -r0 / (r1 - r0);
-    xz = x0 + sz * (x1 - x0);
-    yz = y0 + sz * (y1 - y0);
-    enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
-    theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
-    if (r0 > r1) {
-      theta = -theta;
-    }
+    theta = asin((r1 - r0) / h);
   }
   if (enclosed) {
     a1 = 0;
@@ -4291,59 +4238,101 @@ GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading,
     sMin = 0;
     sMax = 1;
   } else {
-    sMin = 1;
-    sMax = 0;
-    // solve for x(s) + r(s) = xMin
-    if ((x1 + r1) - (x0 + r0) != 0) {
-      sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
-      if (sa < sMin) {
-	sMin = sa;
-      } else if (sa > sMax) {
-	sMax = sa;
-      }
-    }
-    // solve for x(s) - r(s) = xMax
-    if ((x1 - r1) - (x0 - r0) != 0) {
-      sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
-      if (sa < sMin) {
-	sMin = sa;
-      } else if (sa > sMax) {
-	sMax = sa;
-      }
-    }
-    // solve for y(s) + r(s) = yMin
-    if ((y1 + r1) - (y0 + r0) != 0) {
-      sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
-      if (sa < sMin) {
-	sMin = sa;
-      } else if (sa > sMax) {
-	sMax = sa;
-      }
-    }
-    // solve for y(s) - r(s) = yMax
-    if ((y1 - r1) - (y0 - r0) != 0) {
-      sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
-      if (sa < sMin) {
-	sMin = sa;
-      } else if (sa > sMax) {
-	sMax = sa;
-      }
-    }
-    // check against sz
-    if (r0 < r1) {
-      if (sMin < sz) {
-	sMin = sz;
-      }
-    } else if (r0 > r1) {
-      if (sMax > sz) {
-	sMax = sz;
-      }
-    }
-    // check the 'extend' flags
-    if (!shading->getExtend0() && sMin < 0) {
+    // solve x(sLeft) + r(sLeft) = xMin
+    if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) {
+      sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+    } else {
+      sLeft = 0; // make gcc happy
+    }
+    // solve x(sRight) - r(sRight) = xMax
+    if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) {
+      sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+    } else {
+      sRight = 0; // make gcc happy
+    }
+    // solve y(sBottom) + r(sBottom) = yMin
+    if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) {
+      sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+    } else {
+      sBottom = 0; // make gcc happy
+    }
+    // solve y(sTop) - r(sTop) = yMax
+    if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) {
+      sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+    } else {
+      sTop = 0; // make gcc happy
+    }
+    // solve r(sZero) = 0
+    if ((haveSZero = fabs(r1 - r0) > 0.000001)) {
+      sZero = -r0 / (r1 - r0);
+    } else {
+      sZero = 0; // make gcc happy
+    }
+    // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2)
+    if (haveSZero) {
+      sDiag = (sqrt((xMax - xMin) * (xMax - xMin) +
+		    (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
+    } else {
+      sDiag = 0; // make gcc happy
+    }
+    // compute sMin
+    if (shading->getExtend0()) {
+      sMin = 0;
+      haveSMin = gFalse;
+      if (x0 < x1 && haveSLeft && sLeft < 0) {
+	sMin = sLeft;
+	haveSMin = gTrue;
+      } else if (x0 > x1 && haveSRight && sRight < 0) {
+	sMin = sRight;
+	haveSMin = gTrue;
+      }
+      if (y0 < y1 && haveSBottom && sBottom < 0) {
+	if (!haveSMin || sBottom > sMin) {
+	  sMin = sBottom;
+	  haveSMin = gTrue;
+	}
+      } else if (y0 > y1 && haveSTop && sTop < 0) {
+	if (!haveSMin || sTop > sMin) {
+	  sMin = sTop;
+	  haveSMin = gTrue;
+	}
+      }
+      if (haveSZero && sZero < 0) {
+	if (!haveSMin || sZero > sMin) {
+	  sMin = sZero;
+	}
+      }
+    } else {
       sMin = 0;
     }
-    if (!shading->getExtend1() && sMax > 1) {
+    // compute sMax
+    if (shading->getExtend1()) {
+      sMax = 1;
+      haveSMax = gFalse;
+      if (x1 < x0 && haveSLeft && sLeft > 1) {
+	sMax = sLeft;
+	haveSMax = gTrue;
+      } else if (x1 > x0 && haveSRight && sRight > 1) {
+	sMax = sRight;
+	haveSMax = gTrue;
+      }
+      if (y1 < y0 && haveSBottom && sBottom > 1) {
+	if (!haveSMax || sBottom < sMax) {
+	  sMax = sBottom;
+	  haveSMax = gTrue;
+	}
+      } else if (y1 > y0 && haveSTop && sTop > 1) {
+	if (!haveSMax || sTop < sMax) {
+	  sMax = sTop;
+	  haveSMax = gTrue;
+	}
+      }
+      if (haveSZero && sDiag > 1) {
+	if (!haveSMax || sDiag < sMax) {
+	  sMax = sDiag;
+	}
+      }
+    } else {
       sMax = 1;
     }
   }
@@ -4514,13 +4503,14 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) {
   int wMode;
   int *codeToGID;
   GooString *s2;
-  double dx, dy, dx2, dy2, originX, originY;
+  double dx, dy, originX, originY;
   char *p;
   UnicodeMap *uMap;
   CharCode code;
   Unicode *u;
   char buf[8];
-  int len, nChars, uLen, n, m, i, j;
+  double *dxdy;
+  int dxdySize, len, nChars, uLen, n, m, i, j;
 
   // for pdftohtml, output PS without text
   if( displayText == gFalse )
@@ -4549,6 +4539,10 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) {
     for (i = 0; i < font16EncLen; ++i) {
       if (font->getID()->num == font16Enc[i].fontID.num &&
 	  font->getID()->gen == font16Enc[i].fontID.gen) {
+	if (!font16Enc[i].enc) {
+	  // font substitution failed, so don't output any text
+	  return;
+	}
 	uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
 	break;
       }
@@ -4565,63 +4559,89 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) {
     }
   }
 
-  // compute width of chars in string, ignoring char spacing and word
-  // spacing -- the Tj operator will adjust for the metrics of the
-  // font that's actually used
-  dx = dy = 0;
+  // compute the positioning (dx, dy) for each char in the string
   nChars = 0;
   p = s->getCString();
   len = s->getLength();
   s2 = new GooString();
+  dxdySize = font->isCIDFont() ? 8 : s->getLength();
+  dxdy = (double *)gmallocn(2 * dxdySize, sizeof(double));
   while (len > 0) {
     n = font->getNextChar(p, len, &code,
 			  &u, &uLen,
-			  &dx2, &dy2, &originX, &originY);
+			  &dx, &dy, &originX, &originY);
+    dx *= state->getFontSize();
+    dy *= state->getFontSize();
+    if (wMode) {
+      dy += state->getCharSpace();
+      if (n == 1 && *p == ' ') {
+	dy += state->getWordSpace();
+      }
+    } else {
+      dx += state->getCharSpace();
+      if (n == 1 && *p == ' ') {
+	dx += state->getWordSpace();
+      }
+    }
+    dx *= state->getHorizScaling();
     if (font->isCIDFont()) {
       if (uMap) {
+	if (nChars + uLen > dxdySize) {
+	  do {
+	    dxdySize *= 2;
+	  } while (nChars + uLen > dxdySize);
+	  dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double));
+	}
 	for (i = 0; i < uLen; ++i) {
 	  m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
 	  for (j = 0; j < m; ++j) {
 	    s2->append(buf[j]);
 	  }
+	  //~ this really needs to get the number of chars in the target
+	  //~ encoding - which may be more than the number of Unicode
+	  //~ chars
+	  dxdy[2 * nChars] = dx;
+	  dxdy[2 * nChars + 1] = dy;
+	  ++nChars;
 	}
-	//~ this really needs to get the number of chars in the target
-	//~ encoding - which may be more than the number of Unicode
-	//~ chars
-	nChars += uLen;
       } else {
+	if (nChars + 1 > dxdySize) {
+	  dxdySize *= 2;
+	  dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double));
+	}
 	s2->append((char)((code >> 8) & 0xff));
 	s2->append((char)(code & 0xff));
+	dxdy[2 * nChars] = dx;
+	dxdy[2 * nChars + 1] = dy;
 	++nChars;
       }
     } else {
       if (!codeToGID || codeToGID[code] >= 0) {
 	s2->append((char)code);
+	dxdy[2 * nChars] = dx;
+	dxdy[2 * nChars + 1] = dy;
+	++nChars;
       }
     }
-    dx += dx2;
-    dy += dy2;
     p += n;
     len -= n;
   }
-  dx *= state->getFontSize() * state->getHorizScaling();
-  dy *= state->getFontSize();
   if (uMap) {
     uMap->decRefCnt();
   }
 
-  if (s2->getLength() > 0) {
+  if (nChars > 0) {
     writePSString(s2);
-    if (font->isCIDFont()) {
-      if (wMode) {
-	writePSFmt(" {0:d} {1:.6g} Tj16V\n", nChars, dy);
-      } else {
-	writePSFmt(" {0:d} {1:.6g} Tj16\n", nChars, dx);
+    writePS("\n[");
+    for (i = 0; i < 2 * nChars; ++i) {
+      if (i > 0) {
+	writePS("\n");
       }
-    } else {
-      writePSFmt(" {0:.6g} Tj\n", dx);
+      writePSFmt("{0:.6g}", dxdy[i]);
     }
+    writePS("] Tj\n");
   }
+  gfree(dxdy);
   delete s2;
 
   if (state->getRender() & 4) {
@@ -4794,7 +4814,7 @@ void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
       delete str;
     } else {
       // make sure the image is setup, it sometimes is not like on bug #17645
-      setupImage(ref->getRef(), str);
+      setupImage(ref->getRef(), str, gFalse);
       // set up to use the array already created by setupImages()
       writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
     }
@@ -5378,7 +5398,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
       delete str2;
     } else {
       // make sure the image is setup, it sometimes is not like on bug #17645
-      setupImage(ref->getRef(), str);
+      setupImage(ref->getRef(), str, gFalse);
       // set up to use the array already created by setupImages()
       writePSFmt("ImData_{0:d}_{1:d} 0 0\n",ref->getRefNum(), ref->getRefGen());
     }
@@ -5435,7 +5455,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
   // data source
   if (mode == psModeForm || inType3Char || preload) {
     if (inlineImg) {
-      writePS("  /DataSource { 2 copy get exch 1 add exch }\n");
+      writePS("  /DataSource { pdfImStr }\n");
     } else {
       writePS("  /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
 	" index get 1 index get exch 1 add exch }\n");
@@ -5445,18 +5465,26 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
   }
 
   // filters
-  s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
-		       "    ");
-  if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
-      inlineImg || !s) {
-    useRLE = gTrue;
-    useASCII = !(mode == psModeForm || inType3Char || preload);
+  if ((mode == psModeForm || inType3Char || preload) &&
+      globalParams->getPSUncompressPreloadedImages()) {
+    s = NULL;
+    useRLE = gFalse;
     useCompressed = gFalse;
+    useASCII = gFalse;
   } else {
-    useRLE = gFalse;
-    useASCII = str->isBinary() &&
-               !(mode == psModeForm || inType3Char || preload);
-    useCompressed = gTrue;
+    s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+			 "    ");
+    if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+	inlineImg || !s) {
+      useRLE = gTrue;
+      useASCII = !(mode == psModeForm || inType3Char || preload);
+      useCompressed = gFalse;
+    } else {
+      useRLE = gFalse;
+      useASCII = str->isBinary() &&
+	         !(mode == psModeForm || inType3Char || preload);
+      useCompressed = gTrue;
+    }
   }
   if (useASCII) {
     writePSFmt("    /ASCII{0:s}Decode filter\n",
@@ -5594,6 +5622,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   int n, numComps;
   GBool useRLE, useASCII, useASCIIHex, useCompressed;
   GBool maskUseRLE, maskUseASCII, maskUseCompressed;
+  GooString *maskFilters;
   GfxSeparationColorSpace *sepCS;
   GfxColor color;
   GfxCMYK cmyk;
@@ -5603,6 +5632,83 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   useASCIIHex = globalParams->getPSASCIIHex();
   useRLE = useASCII = useCompressed = gFalse; // make gcc happy
   maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
+  maskFilters = NULL; // make gcc happy
+
+  // explicit masking
+  if (maskStr) {
+
+    // mask data source
+    if ((mode == psModeForm || inType3Char || preload) &&
+      globalParams->getPSUncompressPreloadedImages()) {
+      s = NULL;
+      maskUseRLE = gFalse;
+      maskUseCompressed = gFalse;
+      maskUseASCII = gFalse;
+    } else {
+      s = maskStr->getPSFilter(3, "  ");
+      if (!s) {
+	maskUseRLE = gTrue;
+	maskUseASCII = !(mode == psModeForm || inType3Char || preload);
+	maskUseCompressed = gFalse;
+      } else {
+	maskUseRLE = gFalse;
+	maskUseASCII = maskStr->isBinary() &&
+	               !(mode == psModeForm || inType3Char || preload);
+	maskUseCompressed = gTrue;
+      }
+    }
+    maskFilters = new GooString();
+    if (maskUseASCII) {
+      maskFilters->appendf("  /ASCII{0:s}Decode filter\n",
+			   useASCIIHex ? "Hex" : "85");
+    }
+    if (maskUseRLE) {
+      maskFilters->append("  /RunLengthDecode filter\n");
+    }
+    if (maskUseCompressed) {
+      maskFilters->append(s);
+    }
+    if (s) {
+      delete s;
+    }
+    if (mode == psModeForm || inType3Char || preload) {
+      writePSFmt("MaskData_{0:d}_{1:d} pdfMaskInit\n",
+		 ref->getRefNum(), ref->getRefGen());
+    } else {
+      writePS("currentfile\n");
+      writePS(maskFilters->getCString());
+      writePS("pdfMask\n");
+
+      // add RunLengthEncode and ASCIIHex/85 encode filters
+      if (maskUseCompressed) {
+	maskStr = maskStr->getUndecodedStream();
+      }
+      if (maskUseRLE) {
+	maskStr = new RunLengthEncoder(maskStr);
+      }
+      if (maskUseASCII) {
+	if (useASCIIHex) {
+	  maskStr = new ASCIIHexEncoder(maskStr);
+	} else {
+	  maskStr = new ASCII85Encoder(maskStr);
+	}
+      }
+
+      // copy the stream data
+      maskStr->reset();
+      while ((c = maskStr->getChar()) != EOF) {
+	writePSChar(c);
+      }
+      maskStr->close();
+      writePSChar('\n');
+      writePS("%-EOD-\n");
+      
+      // delete encoders
+      if (maskUseRLE || maskUseASCII) {
+	delete maskStr;
+      }
+    }
+  }
 
   // color space
   if (colorMap) {
@@ -5666,7 +5772,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       delete str2;
     } else {
       // make sure the image is setup, it sometimes is not like on bug #17645
-      setupImage(ref->getRef(), str);
+      setupImage(ref->getRef(), str, gFalse);
       // set up to use the array already created by setupImages()
       writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
     }
@@ -5740,7 +5846,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   // data source
   if (mode == psModeForm || inType3Char || preload) {
     if (inlineImg) {
-	writePS("  /DataSource { 2 copy get exch 1 add exch }\n");
+  writePS("  /DataSource { pdfImStr }\n");
     } else {
 	writePS("  /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
 	  " index get 1 index get exch 1 add exch }\n");
@@ -5750,18 +5856,26 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   }
 
   // filters
-  s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
-		       "    ");
-  if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
-      inlineImg || !s) {
-    useRLE = gTrue;
-    useASCII = !(mode == psModeForm || inType3Char || preload);
+  if ((mode == psModeForm || inType3Char || preload) &&
+      globalParams->getPSUncompressPreloadedImages()) {
+    s = NULL;
+    useRLE = gFalse;
     useCompressed = gFalse;
+    useASCII = gFalse;
   } else {
-    useRLE = gFalse;
-    useASCII = str->isBinary() &&
-               !(mode == psModeForm || inType3Char || preload);
-    useCompressed = gTrue;
+    s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+			 "    ");
+    if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+	inlineImg || !s) {
+      useRLE = gTrue;
+      useASCII = !(mode == psModeForm || inType3Char || preload);
+      useCompressed = gFalse;
+    } else {
+      useRLE = gFalse;
+      useASCII = str->isBinary() &&
+                 !(mode == psModeForm || inType3Char || preload);
+      useCompressed = gTrue;
+    }
   }
   if (useASCII) {
     writePSFmt("    /ASCII{0:s}Decode filter\n",
@@ -5794,30 +5908,13 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
 	       maskInvert ? 1 : 0, maskInvert ? 0 : 1);
 
     // mask data source
-    writePS("  /DataSource currentfile\n");
-    s = maskStr->getPSFilter(3, "    ");
-    if (!s) {
-      maskUseRLE = gTrue;
-      maskUseASCII = gTrue;
-      maskUseCompressed = gFalse;
+    if (mode == psModeForm || inType3Char || preload) {
+      writePS("  /DataSource {pdfMaskSrc}\n");
+      writePS(maskFilters->getCString());
     } else {
-      maskUseRLE = gFalse;
-      maskUseASCII = maskStr->isBinary();
-      maskUseCompressed = gTrue;
-    }
-    if (maskUseASCII) {
-      writePSFmt("    /ASCII{0:s}Decode filter\n",
-		 useASCIIHex ? "Hex" : "85");
-    }
-    if (maskUseRLE) {
-      writePS("    /RunLengthDecode filter\n");
-    }
-    if (maskUseCompressed) {
-      writePS(s->getCString());
-    }
-    if (s) {
-      delete s;
+      writePS("  /DataSource maskStream\n");
     }
+    delete maskFilters;
 
     writePS(">>\n");
     writePS(">>\n");
@@ -5845,39 +5942,6 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
 
   }
 
-  // explicit masking
-  if (maskStr) {
-
-    if (maskUseCompressed) {
-      maskStr = maskStr->getUndecodedStream();
-    }
-
-    // add RunLengthEncode and ASCIIHex/85 encode filters
-    if (maskUseRLE) {
-      maskStr = new RunLengthEncoder(maskStr);
-    }
-    if (maskUseASCII) {
-      if (useASCIIHex) {
-	maskStr = new ASCIIHexEncoder(maskStr);
-      } else {
-	maskStr = new ASCII85Encoder(maskStr);
-      }
-    }
-
-    // copy the stream data
-    maskStr->reset();
-    while ((c = maskStr->getChar()) != EOF) {
-      writePSChar(c);
-    }
-    maskStr->close();
-    writePSChar('\n');
-
-    // delete encoders
-    if (maskUseRLE || maskUseASCII) {
-      delete maskStr;
-    }
-  }
-
   // get rid of the array and index
   if (mode == psModeForm || inType3Char || preload) {
     if (!inlineImg) writePS("pop ");
@@ -5926,6 +5990,13 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       delete str;
     }
   }
+
+  // close the mask stream
+  if (maskStr) {
+    if (!(mode == psModeForm || inType3Char || preload)) {
+      writePS("pdfMaskEnd\n");
+    }
+  }
 }
 
 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
@@ -6598,6 +6669,7 @@ void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
   t3URY = ury;
   t3String = new GooString();
   writePS("q\n");
+  t3FillColorOnly = gTrue;
   t3Cacheable = gTrue;
   t3NeedsRestore = gTrue;
 }
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index 4666c06..b2d49af 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -43,16 +43,20 @@
 #include "GlobalParams.h"
 #include "OutputDev.h"
 
+class GHooash;
+class PDFDoc;
+class XRef;
+class Function;
 class GfxPath;
 class GfxFont;
 class GfxColorSpace;
 class GfxSeparationColorSpace;
 class PDFRectangle;
+struct PST1FontName;
 struct PSFont8Info;
 struct PSFont16Enc;
 class PSOutCustomColor;
-class Function;
-class PDFDoc;
+class PSOutputDev;
 
 //------------------------------------------------------------------------
 // PSOutputDev
@@ -72,8 +76,17 @@ enum PSFileType {
   psGeneric			// write to a generic stream
 };
 
+enum PSOutCustomCodeLocation {
+  psOutCustomDocSetup,
+  psOutCustomPageSetup
+};
+
 typedef void (*PSOutputFunc)(void *stream, const char *data, int len);
 
+typedef GooString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut,
+				       PSOutCustomCodeLocation loc, int n, 
+				       void *data);
+
 class PSOutputDev: public OutputDev {
 public:
 
@@ -85,8 +98,9 @@ public:
 	      GBool duplexA = gTrue,
 	      int imgLLXA = 0, int imgLLYA = 0,
 	      int imgURXA = 0, int imgURYA = 0,
-	      GBool forceRasterizeA = gFalse,
-	      GBool manualCtrlA = gFalse);
+	      GBool manualCtrlA = gFalse,
+	      PSOutCustomCodeCbk customCodeCbkA = NULL,
+	      void *customCodeCbkDataA = NULL);
 
   // Open a PSOutputDev that will write to a generic stream.
   PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
@@ -97,8 +111,9 @@ public:
 	      GBool duplexA = gTrue,
 	      int imgLLXA = 0, int imgLLYA = 0,
 	      int imgURXA = 0, int imgURYA = 0,
-	      GBool forceRasterizeA = gFalse,
-	      GBool manualCtrlA = gFalse);
+	      GBool manualCtrlA = gFalse,
+	      PSOutCustomCodeCbk customCodeCbkA = NULL,
+	      void *customCodeCbkDataA = NULL);
 
   // Destructor -- writes the trailer and closes the file.
   virtual ~PSOutputDev();
@@ -310,7 +325,7 @@ private:
   void setupType3Font(GfxFont *font, GooString *psName, Dict *parentResDict);
   GooString *makePSFontName(GfxFont *font, Ref *id);
   void setupImages(Dict *resDict);
-  void setupImage(Ref id, Stream *str);
+  void setupImage(Ref id, Stream *str, GBool mask);
   void setupForms(Dict *resDict);
   void setupForm(Ref id, Object *strObj);
   void addProcessColor(double c, double m, double y, double k);
@@ -376,6 +391,7 @@ private:
   PSOutMode mode;		// PostScript mode (PS, EPS, form)
   int paperWidth;		// width of paper, in pts
   int paperHeight;		// height of paper, in pts
+  GBool paperMatch;		// true if paper size is set to match each page
   int prevWidth;		// width of previous page
                                 // (only psModePSOrigPageSizes output mode)
   int prevHeight;		// height of previous page
@@ -394,6 +410,10 @@ private:
   void *underlayCbkData;
   void (*overlayCbk)(PSOutputDev *psOut, void *data);
   void *overlayCbkData;
+  GooString *(*customCodeCbk)(PSOutputDev *psOut,
+			    PSOutCustomCodeLocation loc, int n, 
+			    void *data);
+  void *customCodeCbkData;
 
   PDFDoc *doc;
   XRef *xref;			// the xref table for this PDF file
@@ -402,15 +422,9 @@ private:
   int fontIDLen;		// number of entries in fontIDs array
   int fontIDSize;		// size of fontIDs array
   GooHash *fontNames;		// all used font names
-  Ref *fontFileIDs;		// list of object IDs of all embedded fonts
-  int fontFileIDLen;		// number of entries in fontFileIDs array
-  int fontFileIDSize;		// size of fontFileIDs array
-  GooString **fontFileNames;	// list of names of all embedded external fonts
-  GooString **psFileNames;	// list of names of all embedded external fonts
-  int fontFileNameLen;		// number of entries in fontFileNames array
-  int fontFileNameSize;		// size of fontFileNames array
-  int nextTrueTypeNum;		// next unique number to append to a TrueType
-				//   font name
+  PST1FontName *t1FontNames;	// font names for Type 1/1C fonts
+  int t1FontNameLen;		// number of entries in t1FontNames array
+  int t1FontNameSize;		// size of t1FontNames array
   PSFont8Info *font8Info;	// info for 8-bit fonts
   int font8InfoLen;		// number of entries in font8Info array
   int font8InfoSize;		// size of font8Info array
@@ -429,6 +443,8 @@ private:
   int numTilingPatterns;	// current number of nested tiling patterns
   int nextFunc;			// next unique number to use for a function
 
+  GooList *paperSizes;		// list of used paper sizes, if paperMatch
+				//   is true [PSOutPaperSize]
   double tx0, ty0;		// global translation
   double xScale0, yScale0;	// global scaling
   int rotate0;			// rotation angle (0, 90, 180, 270)
@@ -453,9 +469,9 @@ private:
   GooString *t3String;		// Type 3 content string
   double t3WX, t3WY,		// Type 3 character parameters
          t3LLX, t3LLY, t3URX, t3URY;
+  GBool t3FillColorOnly;	// operators should only use the fill color
   GBool t3Cacheable;		// cleared if char is not cacheable
   GBool t3NeedsRestore;		// set if a 'q' operator was issued
-  GBool forceRasterize;		// forces the page to be rasterized into a image before printing
   GBool displayText;		// displayText
 
 #if OPI_SUPPORT
@@ -465,7 +481,6 @@ private:
 
   GBool ok;			// set up ok?
 
-
   friend class WinPDFPrinter;
 };
 
diff --git a/poppler/Parser.cc b/poppler/Parser.cc
index 03b836e..400d8d7 100644
--- a/poppler/Parser.cc
+++ b/poppler/Parser.cc
@@ -59,10 +59,11 @@ Parser::~Parser() {
 
 Object *Parser::getObj(Object *obj, int recursion)
 {
-  return getObj(obj, NULL, cryptRC4, 0, 0, 0, recursion);
+  return getObj(obj, gFalse, NULL, cryptRC4, 0, 0, 0, recursion);
 }
 
-Object *Parser::getObj(Object *obj, Guchar *fileKey,
+Object *Parser::getObj(Object *obj, GBool simpleOnly,
+           Guchar *fileKey,
 		       CryptAlgorithm encAlgorithm, int keyLength,
 		       int objNum, int objGen, int recursion) {
   char *key;
@@ -83,18 +84,18 @@ Object *Parser::getObj(Object *obj, Guchar *fileKey,
   }
 
   // array
-  if (likely(recursion < recursionLimit) && buf1.isCmd("[")) {
+  if (!simpleOnly && likely(recursion < recursionLimit) && buf1.isCmd("[")) {
     shift();
     obj->initArray(xref);
     while (!buf1.isCmd("]") && !buf1.isEOF())
-      obj->arrayAdd(getObj(&obj2, fileKey, encAlgorithm, keyLength,
+      obj->arrayAdd(getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength,
 			   objNum, objGen, recursion + 1));
     if (buf1.isEOF())
       error(errSyntaxError, getPos(), "End of file inside array");
     shift();
 
   // dictionary or stream
-  } else if (likely(recursion < recursionLimit) && buf1.isCmd("<<")) {
+  } else if (!simpleOnly && likely(recursion < recursionLimit) && buf1.isCmd("<<")) {
     shift(objNum);
     obj->initDict(xref);
     while (!buf1.isCmd(">>") && !buf1.isEOF()) {
@@ -109,7 +110,7 @@ Object *Parser::getObj(Object *obj, Guchar *fileKey,
 	  gfree(key);
 	  break;
 	}
-	obj->dictAdd(key, getObj(&obj2, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1));
+	obj->dictAdd(key, getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1));
       }
     }
     if (buf1.isEOF())
diff --git a/poppler/Parser.h b/poppler/Parser.h
index f1fa765..69cfc25 100644
--- a/poppler/Parser.h
+++ b/poppler/Parser.h
@@ -42,8 +42,11 @@ public:
   // Destructor.
   ~Parser();
 
-  // Get the next object from the input stream.
-  Object *getObj(Object *obj, Guchar *fileKey = NULL,
+  // Get the next object from the input stream.  If <simpleOnly> is
+  // true, do not parse compound objects (arrays, dictionaries, or
+  // streams).
+  Object *getObj(Object *obj, GBool simpleOnly = gFalse, 
+     Guchar *fileKey = NULL,
 		 CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0,
 		 int objNum = 0, int objGen = 0, int recursion = 0);
   
diff --git a/poppler/PreScanOutputDev.cc b/poppler/PreScanOutputDev.cc
index d77bb5a..3a86d52 100644
--- a/poppler/PreScanOutputDev.cc
+++ b/poppler/PreScanOutputDev.cc
@@ -95,6 +95,46 @@ GBool PreScanOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *ca
   return gTrue;
 }
 
+GBool PreScanOutputDev::functionShadedFill(GfxState *state,
+					   GfxFunctionShading *shading) {
+  if (shading->getColorSpace()->getMode() != csDeviceGray &&
+      shading->getColorSpace()->getMode() != csCalGray) {
+    gray = gFalse;
+  }
+  mono = gFalse;
+  if (state->getFillOpacity() != 1 ||
+      state->getBlendMode() != gfxBlendNormal) {
+    transparency = gTrue;
+  }
+  return gTrue;
+}
+
+GBool PreScanOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/) {
+  if (shading->getColorSpace()->getMode() != csDeviceGray &&
+      shading->getColorSpace()->getMode() != csCalGray) {
+    gray = gFalse;
+  }
+  mono = gFalse;
+  if (state->getFillOpacity() != 1 ||
+      state->getBlendMode() != gfxBlendNormal) {
+    transparency = gTrue;
+  }
+  return gTrue;
+}
+
+GBool PreScanOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/) {
+  if (shading->getColorSpace()->getMode() != csDeviceGray &&
+      shading->getColorSpace()->getMode() != csCalGray) {
+    gray = gFalse;
+  }
+  mono = gFalse;
+  if (state->getFillOpacity() != 1 ||
+      state->getBlendMode() != gfxBlendNormal) {
+    transparency = gTrue;
+  }
+  return gTrue;
+}
+
 void PreScanOutputDev::clip(GfxState * /*state*/) {
   //~ check for a rectangle "near" the edge of the page;
   //~   else set gdi to false
@@ -161,7 +201,7 @@ void PreScanOutputDev::drawImageMask(GfxState *state, Object * /*ref*/, Stream *
   gdi = gFalse;
   if ((level == psLevel1 || level == psLevel1Sep) &&
       state->getFillColorSpace()->getMode() == csPattern) {
-    level1PSBug = gTrue;
+    patternImgMask = gTrue;
   }
 
   if (inlineImg) {
@@ -184,12 +224,17 @@ void PreScanOutputDev::drawImage(GfxState *state, Object * /*ref*/, Stream *str,
   if (colorSpace->getMode() == csIndexed) {
     colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
   }
-  if (colorSpace->getMode() != csDeviceGray &&
-      colorSpace->getMode() != csCalGray) {
+  if (colorSpace->getMode() == csDeviceGray ||
+      colorSpace->getMode() == csCalGray) {
+    if (colorMap->getBits() > 1) {
+      mono = gFalse;
+    }
+  } else {
     gray = gFalse;
+    mono = gFalse;
   }
-  mono = gFalse;
-  if (state->getBlendMode() != gfxBlendNormal) {
+  if (state->getFillOpacity() != 1 ||
+      state->getBlendMode() != gfxBlendNormal) {
     transparency = gTrue;
   }
   gdi = gFalse;
@@ -218,12 +263,17 @@ void PreScanOutputDev::drawMaskedImage(GfxState *state, Object * /*ref*/,
   if (colorSpace->getMode() == csIndexed) {
     colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
   }
-  if (colorSpace->getMode() != csDeviceGray &&
-      colorSpace->getMode() != csCalGray) {
+  if (colorSpace->getMode() == csDeviceGray ||
+      colorSpace->getMode() == csCalGray) {
+    if (colorMap->getBits() > 1) {
+      mono = gFalse;
+    }
+  } else {
     gray = gFalse;
+    mono = gFalse;
   }
-  mono = gFalse;
-  if (state->getBlendMode() != gfxBlendNormal) {
+  if (state->getFillOpacity() != 1 ||
+      state->getBlendMode() != gfxBlendNormal) {
     transparency = gTrue;
   }
   gdi = gFalse;
@@ -303,5 +353,5 @@ void PreScanOutputDev::clearStats() {
   gray = gTrue;
   transparency = gFalse;
   gdi = gTrue;
-  level1PSBug = gFalse;
+  patternImgMask = gFalse;
 }
diff --git a/poppler/PreScanOutputDev.h b/poppler/PreScanOutputDev.h
index ac147f3..5260a3b 100644
--- a/poppler/PreScanOutputDev.h
+++ b/poppler/PreScanOutputDev.h
@@ -64,6 +64,11 @@ public:
   // operations.
   virtual GBool useTilingPatternFill() { return gTrue; }
 
+  // Does this device use functionShadedFill(), axialShadedFill(), and
+  // radialShadedFill()?  If this returns false, these shaded fills
+  // will be reduced to a series of other drawing operations.
+  virtual GBool useShadedFills(int type) { return gTrue; }
+
   // Does this device use beginType3Char/endType3Char?  Otherwise,
   // text in Type 3 fonts will be drawn with drawChar/drawString.
   virtual GBool interpretType3Chars() { return gTrue; }
@@ -85,6 +90,10 @@ public:
 				  double *mat, double *bbox,
 				  int x0, int y0, int x1, int y1,
 				  double xStep, double yStep);
+  virtual GBool functionShadedFill(GfxState *state,
+				   GfxFunctionShading *shading);
+  virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax);
+  virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading, double tMin, double tMax);
 
   //----- path clipping
   virtual void clip(GfxState *state);
@@ -148,8 +157,9 @@ public:
   GBool isAllGDI() { return gdi; }
 
   // Returns true if the operations performed since the last call to
-  // clearStats() processed a feature that PSOutputDev does not implement.
-  GBool hasLevel1PSBug() { return level1PSBug; }
+  // clearStats() included any image mask fills with a pattern color
+  // space. (only level1!)
+  GBool usesPatternImageMask() { return patternImgMask; }
 
   // Clear the stats used by the above functions.
   void clearStats();
@@ -165,7 +175,7 @@ private:
   GBool transparency;
   GBool gdi;
   PSLevel level;		// PostScript level (1, 2, separation)
-  GBool level1PSBug;		// gTrue if it uses a feature not supported in PSOutputDev
+  GBool patternImgMask;		
 };
 
 #endif
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index c455d6a..9fdb7c0 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -260,6 +260,7 @@ void XRef::init() {
   entries = NULL;
   capacity = 0;
   size = 0;
+  last = -1;
   streamEnds = NULL;
   streamEndsLen = 0;
   objStrs = new PopplerCache(5);
@@ -430,7 +431,7 @@ GBool XRef::readXRef(Guint *pos, std::vector<Guint> *followedXRefStm) {
 	     new Lexer(NULL,
 	       str->makeSubStream(start + *pos, gFalse, 0, &obj)),
 	     gTrue);
-  parser->getObj(&obj);
+  parser->getObj(&obj, gTrue);
 
   // parse an old-style xref table
   if (obj.isCmd("xref")) {
@@ -440,11 +441,11 @@ GBool XRef::readXRef(Guint *pos, std::vector<Guint> *followedXRefStm) {
   // parse an xref stream
   } else if (obj.isInt()) {
     obj.free();
-    if (!parser->getObj(&obj)->isInt()) {
+    if (!parser->getObj(&obj, gTrue)->isInt()) {
       goto err1;
     }
     obj.free();
-    if (!parser->getObj(&obj)->isCmd("obj")) {
+    if (!parser->getObj(&obj, gTrue)->isCmd("obj")) {
       goto err1;
     }
     obj.free();
@@ -479,7 +480,7 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *follow
   int first, n, i;
 
   while (1) {
-    parser->getObj(&obj);
+    parser->getObj(&obj, gTrue);
     if (obj.isCmd("trailer")) {
       obj.free();
       break;
@@ -489,7 +490,7 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *follow
     }
     first = obj.getInt();
     obj.free();
-    if (!parser->getObj(&obj)->isInt()) {
+    if (!parser->getObj(&obj, gTrue)->isInt()) {
       goto err1;
     }
     n = obj.getInt();
@@ -504,19 +505,19 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *follow
       }
     }
     for (i = first; i < first + n; ++i) {
-      if (!parser->getObj(&obj)->isInt()) {
+      if (!parser->getObj(&obj, gTrue)->isInt()) {
 	goto err1;
       }
       entry.offset = (Guint)obj.getInt();
       obj.free();
-      if (!parser->getObj(&obj)->isInt()) {
+      if (!parser->getObj(&obj, gTrue)->isInt()) {
 	goto err1;
       }
       entry.gen = obj.getInt();
       entry.obj.initNull ();
       entry.updated = false;
       obj.free();
-      parser->getObj(&obj);
+      parser->getObj(&obj, gTrue);
       if (obj.isCmd("n")) {
 	entry.type = xrefEntryUncompressed;
       } else if (obj.isCmd("f")) {
@@ -537,6 +538,9 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *follow
 	  entries[0] = entries[1];
 	  entries[1].offset = 0xffffffff;
 	}
+	if (i > last) {
+	  last = i;
+	}
       }
     }
   }
@@ -549,13 +553,25 @@ GBool XRef::readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *follow
   // get the 'Prev' pointer
   obj.getDict()->lookupNF("Prev", &obj2);
   if (obj2.isInt()) {
-    *pos = (Guint)obj2.getInt();
-    more = gTrue;
+    pos2 = (Guint)obj2.getInt();
+    if (pos2 != *pos) {
+      *pos = pos2;
+      more = gTrue;
+    } else {
+      error(errSyntaxWarning, -1, "Infinite loop in xref table");
+      more = gFalse;
+    }
   } else if (obj2.isRef()) {
     // certain buggy PDF generators generate "/Prev NNN 0 R" instead
     // of "/Prev NNN"
-    *pos = (Guint)obj2.getRefNum();
-    more = gTrue;
+    pos2 = (Guint)obj2.getRefNum();
+    if (pos2 != *pos) {
+      *pos = pos2;
+      more = gTrue;
+    } else {
+      error(errSyntaxWarning, -1, "Infinite loop in xref table");
+      more = gFalse;
+    }
   } else {
     more = gFalse;
   }
@@ -743,6 +759,9 @@ GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
       default:
 	return gFalse;
       }
+      if (i > last) {
+	last = i;
+      }
     }
   }
 
@@ -769,7 +788,6 @@ GBool XRef::constructXRef(GBool *wasReconstructed) {
   size = 0;
   entries = NULL;
 
-  error(errSyntaxWarning, -1, "PDF file is damaged - attempting to reconstruct xref table...");
   gotRoot = gFalse;
   streamEndsLen = streamEndsSize = 0;
 
@@ -826,32 +844,32 @@ GBool XRef::constructXRef(GBool *wasReconstructed) {
         delete parser;
 
       // look for object
-      } else if (*p > 0 && isdigit(*p)) {
-        num = atoi(p);
-        if (num > 0) {
+    } else if (isdigit(*p & 0xff)) {
+      num = atoi(p);
+      if (num > 0) {
+	do {
+	  ++p;
+	} while (*p && isdigit(*p & 0xff));
+	if (isspace(*p & 0xff)) {
 	  do {
 	    ++p;
-	  } while (*p > 0 && isdigit(*p));
-	  if (*p > 0 && isspace(*p)) {
+	  } while (*p && isspace(*p & 0xff));
+	  if (isdigit(*p & 0xff)) {
+	    gen = atoi(p);
 	    do {
 	      ++p;
-	    } while (*p > 0 && isspace(*p));
-	    if (*p > 0 && isdigit(*p)) {
-	      gen = atoi(p);
+	    } while (*p && isdigit(*p & 0xff));
+	    if (isspace(*p & 0xff)) {
 	      do {
-	        ++p;
-	      } while (*p > 0 && isdigit(*p));
-	      if (*p > 0 && isspace(*p)) {
-	        do {
-		  ++p;
-	        } while (*p > 0 && isspace(*p));
-	        if (!strncmp(p, "obj", 3)) {
-		  if (num >= size) {
-		    newSize = (num + 1 + 255) & ~255;
-		    if (newSize < 0) {
-		      error(errSyntaxError, -1, "Bad object number");
-		      return gFalse;
-		    }
+		++p;
+	      } while (*p && isspace(*p & 0xff));
+	      if (!strncmp(p, "obj", 3)) {
+		if (num >= size) {
+		  newSize = (num + 1 + 255) & ~255;
+		  if (newSize < 0) {
+		    error(errSyntaxError, -1, "Bad object number");
+		    return gFalse;
+		  }
 		    if (resize(newSize) != newSize) {
 		      error(errSyntaxError, -1, "Invalid 'obj' parameters");
 		      return gFalse;
@@ -862,7 +880,10 @@ GBool XRef::constructXRef(GBool *wasReconstructed) {
 		    entries[num].offset = pos - start;
 		    entries[num].gen = gen;
 		    entries[num].type = xrefEntryUncompressed;
+		  if (num > last) {
+		    last = num;
 		  }
+		}
 	        }
 	      }
 	    }
@@ -1030,7 +1051,7 @@ Object *XRef::fetch(int num, int gen, Object *obj, int recursion) {
       delete parser;
       goto err;
     }
-    parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL,
+    parser->getObj(obj, gFalse, encrypted ? fileKey : (Guchar *)NULL,
 		   encAlgorithm, keyLength, num, gen, recursion);
     obj1.free();
     obj2.free();
diff --git a/poppler/XRef.h b/poppler/XRef.h
index adfdc1a..848947c 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -109,7 +109,7 @@ public:
   Object *getDocInfoNF(Object *obj);
 
   // Return the number of objects in the xref table.
-  int getNumObjects() { return size; }
+  int getNumObjects() { return last + 1; }
 
   // Return the catalog object reference.
   int getRootNum() { return rootNum; }
@@ -141,6 +141,7 @@ private:
   XRefEntry *entries;		// xref entries
   int capacity;			// size of <entries> array
   int size;			// number of entries
+  int last;			// last used index in <entries>
   int rootNum, rootGen;		// catalog dict
   GBool ok;			// true if xref table is valid
   int errCode;			// error code (if <ok> is false)
diff --git a/utils/pdftops.cc b/utils/pdftops.cc
index 7f5f511..542838b 100644
--- a/utils/pdftops.cc
+++ b/utils/pdftops.cc
@@ -273,7 +273,7 @@ int main(int argc, char *argv[]) {
     globalParams->setPSLevel(level);
   }
   if (splashResolution > 0) {
-    globalParams->setSplashResolution(splashResolution);
+    globalParams->setPSRasterResolution(splashResolution);
   }
   if (noEmbedT1Fonts) {
     globalParams->setPSEmbedType1(!noEmbedT1Fonts);


More information about the poppler mailing list