[poppler] goo/ImgWriter.h goo/JpegWriter.cc goo/JpegWriter.h poppler/Gfx.cc poppler/GfxState.cc poppler/GfxState.h poppler/OutputDev.h poppler/SplashOutputDev.cc poppler/SplashOutputDev.h splash/SplashBitmap.cc splash/SplashBitmap.h splash/Splash.cc splash/Splash.h splash/SplashPattern.cc splash/SplashPattern.h splash/SplashState.cc splash/SplashState.h splash/SplashTypes.h utils/pdftoppm.cc

Albert Astals Cid aacid at kemper.freedesktop.org
Thu Jul 28 15:33:25 PDT 2011


 goo/ImgWriter.h            |    2 
 goo/JpegWriter.cc          |   54 ++++++-
 goo/JpegWriter.h           |    7 -
 poppler/Gfx.cc             |   98 +++++++++++++-
 poppler/GfxState.cc        |    1 
 poppler/GfxState.h         |    4 
 poppler/OutputDev.h        |    1 
 poppler/SplashOutputDev.cc |  307 +++++++++++++++++++++++++++++++++++++++------
 poppler/SplashOutputDev.h  |   51 ++++++-
 splash/Splash.cc           |   86 +++++++++---
 splash/Splash.h            |    9 -
 splash/SplashBitmap.cc     |   64 +++++++++
 splash/SplashBitmap.h      |    1 
 splash/SplashPattern.cc    |   16 ++
 splash/SplashPattern.h     |    7 +
 splash/SplashState.cc      |   11 +
 splash/SplashState.h       |   22 +++
 splash/SplashTypes.h       |    5 
 utils/pdftoppm.cc          |   36 ++++-
 19 files changed, 686 insertions(+), 96 deletions(-)

New commits:
commit 861a7bfb9431609e1e148240447f23c8e83b9d0f
Author: Thomas Freitag <Thomas.Freitag at alfa.de>
Date:   Fri Jul 29 00:30:58 2011 +0200

    Implement overprint in Splash
    
    See the "Implementing overprint in Splash" thread in the mailing list for more info

diff --git a/goo/ImgWriter.h b/goo/ImgWriter.h
index 50fe9d7..185c230 100644
--- a/goo/ImgWriter.h
+++ b/goo/ImgWriter.h
@@ -8,6 +8,7 @@
 // Copyright (C) 2009, 2011 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2010 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2010 Brian Cameron <brian.cameron at oracle.com>
+// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 //========================================================================
 
@@ -26,6 +27,7 @@ class ImgWriter
 		virtual bool writeRow(unsigned char **row) = 0;
 		
 		virtual bool close() = 0;
+		virtual bool supportCMYK() { return false; }
 };
 
 #endif
diff --git a/goo/JpegWriter.cc b/goo/JpegWriter.cc
index c9b7052..7ed5d52 100644
--- a/goo/JpegWriter.cc
+++ b/goo/JpegWriter.cc
@@ -7,6 +7,7 @@
 // Copyright (C) 2009 Stefan Thomas <thomas at eload24.com>
 // Copyright (C) 2010 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2010 Harry Roberts <harry.roberts at midnight-labs.org>
+// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 //========================================================================
 
@@ -27,13 +28,13 @@ void outputMessage(j_common_ptr cinfo)
 	error(-1, "%s", buffer);
 }
 
-JpegWriter::JpegWriter(int q, bool p)
-: progressive(p), quality(q)
+JpegWriter::JpegWriter(int q, bool p, J_COLOR_SPACE cm)
+: progressive(p), quality(q), colorMode(cm)
 {
 }
 
-JpegWriter::JpegWriter()
-: progressive(false), quality(-1)
+JpegWriter::JpegWriter(J_COLOR_SPACE cm)
+: progressive(false), quality(-1), colorMode(cm)
 {
 }
 
@@ -61,9 +62,26 @@ bool JpegWriter::init(FILE *f, int width, int height, int hDPI, int vDPI)
 	cinfo.density_unit = 1; // dots per inch
 	cinfo.X_density = hDPI;
 	cinfo.Y_density = vDPI;
-	cinfo.input_components = 3;     /* # of color components per pixel */
-	cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+	cinfo.in_color_space = colorMode; /* colorspace of input image */
+	/* # of color components per pixel */
+	switch (colorMode) {
+		case JCS_GRAYSCALE:
+			cinfo.input_components = 1;     
+			break;
+		case JCS_RGB:
+			cinfo.input_components = 3;     
+			break;
+		case JCS_CMYK:
+			cinfo.input_components = 4;     
+			break;
+		default:
+			return false;
+	}
 	jpeg_set_defaults(&cinfo);
+	if (cinfo.in_color_space == JCS_CMYK) {
+		jpeg_set_colorspace(&cinfo, JCS_YCCK);
+		cinfo.write_JFIF_header = TRUE;
+	}
 	
 	// Set quality
 	if( quality >= 0 && quality <= 100 ) { 
@@ -83,16 +101,36 @@ bool JpegWriter::init(FILE *f, int width, int height, int hDPI, int vDPI)
 
 bool JpegWriter::writePointers(unsigned char **rowPointers, int rowCount)
 {
+	if (colorMode == JCS_CMYK) {
+		for (int y = 0; y < rowCount; y++) {
+			unsigned char *row = rowPointers[y];
+			for (unsigned int x = 0; x < cinfo.image_width; x++) {
+				for (int n = 0; n < 4; n++) {
+					*row = 0xff - *row;
+					row++;
+				}
+			}
+		}
+	}
 	// Write all rows to the file
 	jpeg_write_scanlines(&cinfo, rowPointers, rowCount);
 	
 	return true;
 }
 
-bool JpegWriter::writeRow(unsigned char **row)
+bool JpegWriter::writeRow(unsigned char **rowPointer)
 {
+	if (colorMode == JCS_CMYK) {
+		unsigned char *row = rowPointer[0];
+		for (unsigned int x = 0; x < cinfo.image_width; x++) {
+			for (int n = 0; n < 4; n++) {
+				*row = 0xff - *row;
+				row++;
+			}
+		}
+	}
 	// Write the row to the file
-	jpeg_write_scanlines(&cinfo, row, 1);
+	jpeg_write_scanlines(&cinfo, rowPointer, 1);
 	
 	return true;
 }
diff --git a/goo/JpegWriter.h b/goo/JpegWriter.h
index cd2a035..7af6870 100644
--- a/goo/JpegWriter.h
+++ b/goo/JpegWriter.h
@@ -10,6 +10,7 @@
 // Copyright (C) 2010 Harry Roberts <harry.roberts at midnight-labs.org>
 // Copyright (C) 2010 Brian Cameron <brian.cameron at oracle.com>
 // Copyright (C) 2011 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 //========================================================================
 
@@ -30,8 +31,8 @@ extern "C" {
 class JpegWriter : public ImgWriter
 {
 	public:
-		JpegWriter(int quality, bool progressive);
-		JpegWriter();
+		JpegWriter(int quality, bool progressive, J_COLOR_SPACE colorMode = JCS_RGB);
+		JpegWriter(J_COLOR_SPACE colorMode = JCS_RGB);
 		~JpegWriter();
 		
 		bool init(FILE *f, int width, int height, int hDPI, int vDPI);
@@ -40,10 +41,12 @@ class JpegWriter : public ImgWriter
 		bool writeRow(unsigned char **row);
 		
 		bool close();
+		bool supportCMYK() { return colorMode == JCS_CMYK; }
 	
 	private:
 		bool progressive;
 		int quality;
+		J_COLOR_SPACE colorMode;
 		struct jpeg_compress_struct cinfo;
 		struct jpeg_error_mgr jerr;
 };
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index dc5f8e3..ca93477 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -1021,6 +1021,11 @@ void Gfx::opSetExtGState(Object args[], int numArgs) {
     }
   }
   obj2.free();
+  if (obj1.dictLookup("OPM", &obj2)->isInt()) {
+    state->setOverprintMode(obj2.getInt());
+    out->updateOverprintMode(state);
+  }
+  obj2.free();
 
   // stroke adjust
   if (obj1.dictLookup("SA", &obj2)->isBool()) {
@@ -1314,6 +1319,8 @@ void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
 
 void Gfx::opSetFillGray(Object args[], int numArgs) {
   GfxColor color;
+  GfxColorSpace *colorSpace;
+  Object obj;
 
   if (textHaveCSPattern && drawText) {
     GBool needFill = out->deviceHasTextClip(state);
@@ -1324,7 +1331,14 @@ void Gfx::opSetFillGray(Object args[], int numArgs) {
     out->restoreState(state);
   }
   state->setFillPattern(NULL);
-  state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+  res->lookupColorSpace("DefaultGray", &obj);
+  if (obj.isNull()) {
+    colorSpace = new GfxDeviceGrayColorSpace();
+  } else {
+    colorSpace = GfxColorSpace::parse(&obj, this);
+  }
+  obj.free();
+  state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
   color.c[0] = dblToCol(args[0].getNum());
   state->setFillColor(&color);
@@ -1340,9 +1354,18 @@ void Gfx::opSetFillGray(Object args[], int numArgs) {
 
 void Gfx::opSetStrokeGray(Object args[], int numArgs) {
   GfxColor color;
+  GfxColorSpace *colorSpace;
+  Object obj;
 
   state->setStrokePattern(NULL);
-  state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+  res->lookupColorSpace("DefaultGray", &obj);
+  if (obj.isNull()) {
+    colorSpace = new GfxDeviceGrayColorSpace();
+  } else {
+    colorSpace = GfxColorSpace::parse(&obj, this);
+  }
+  obj.free();
+  state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   color.c[0] = dblToCol(args[0].getNum());
   state->setStrokeColor(&color);
@@ -1351,6 +1374,8 @@ void Gfx::opSetStrokeGray(Object args[], int numArgs) {
 
 void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
   GfxColor color;
+  GfxColorSpace *colorSpace;
+  Object obj;
   int i;
 
   if (textHaveCSPattern && drawText) {
@@ -1361,8 +1386,15 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
     }
     out->restoreState(state);
   }
+  res->lookupColorSpace("DefaultCMYK", &obj);
+  if (obj.isNull()) {
+    colorSpace = new GfxDeviceCMYKColorSpace();
+  } else {
+    colorSpace = GfxColorSpace::parse(&obj, this);
+  }
+  obj.free();
   state->setFillPattern(NULL);
-  state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
+  state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
   for (i = 0; i < 4; ++i) {
     color.c[i] = dblToCol(args[i].getNum());
@@ -1380,10 +1412,19 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
 
 void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
   GfxColor color;
+  GfxColorSpace *colorSpace;
+  Object obj;
   int i;
 
   state->setStrokePattern(NULL);
-  state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
+  res->lookupColorSpace("DefaultCMYK", &obj);
+  if (obj.isNull()) {
+    colorSpace = new GfxDeviceCMYKColorSpace();
+  } else {
+    colorSpace = GfxColorSpace::parse(&obj, this);
+  }
+  obj.free();
+  state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   for (i = 0; i < 4; ++i) {
     color.c[i] = dblToCol(args[i].getNum());
@@ -1393,6 +1434,8 @@ void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
 }
 
 void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
+  Object obj;
+  GfxColorSpace *colorSpace;
   GfxColor color;
   int i;
 
@@ -1405,7 +1448,14 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
     out->restoreState(state);
   }
   state->setFillPattern(NULL);
-  state->setFillColorSpace(new GfxDeviceRGBColorSpace());
+  res->lookupColorSpace("DefaultRGB", &obj);
+  if (obj.isNull()) {
+    colorSpace = new GfxDeviceRGBColorSpace();
+  } else {
+    colorSpace = GfxColorSpace::parse(&obj, this);
+  }
+  obj.free();
+  state->setFillColorSpace(colorSpace);
   out->updateFillColorSpace(state);
   for (i = 0; i < 3; ++i) {
     color.c[i] = dblToCol(args[i].getNum());
@@ -1422,11 +1472,20 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
 }
 
 void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
+  Object obj;
+  GfxColorSpace *colorSpace;
   GfxColor color;
   int i;
 
   state->setStrokePattern(NULL);
-  state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
+  res->lookupColorSpace("DefaultRGB", &obj);
+  if (obj.isNull()) {
+    colorSpace = new GfxDeviceRGBColorSpace();
+  } else {
+    colorSpace = GfxColorSpace::parse(&obj, this);
+  }
+  obj.free();
+  state->setStrokeColorSpace(colorSpace);
   out->updateStrokeColorSpace(state);
   for (i = 0; i < 3; ++i) {
     color.c[i] = dblToCol(args[i].getNum());
@@ -4132,11 +4191,32 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
     if (!obj1.isNull()) {
       colorSpace = GfxColorSpace::parse(&obj1, this);
     } else if (csMode == streamCSDeviceGray) {
-      colorSpace = new GfxDeviceGrayColorSpace();
+      Object objCS;
+      res->lookupColorSpace("DefaultGray", &objCS);
+      if (objCS.isNull()) {
+        colorSpace = new GfxDeviceGrayColorSpace();
+      } else {
+        colorSpace = GfxColorSpace::parse(&objCS, this);
+      }
+      objCS.free();
     } else if (csMode == streamCSDeviceRGB) {
-      colorSpace = new GfxDeviceRGBColorSpace();
+      Object objCS;
+      res->lookupColorSpace("DefaultRGB", &objCS);
+      if (objCS.isNull()) {
+        colorSpace = new GfxDeviceRGBColorSpace();
+      } else {
+        colorSpace = GfxColorSpace::parse(&objCS, this);
+      }
+      objCS.free();
     } else if (csMode == streamCSDeviceCMYK) {
-      colorSpace = new GfxDeviceCMYKColorSpace();
+      Object objCS;
+      res->lookupColorSpace("DefaultCMYK", &objCS);
+      if (objCS.isNull()) {
+        colorSpace = new GfxDeviceCMYKColorSpace();
+      } else {
+        colorSpace = GfxColorSpace::parse(&objCS, this);
+      }
+      objCS.free();
     } else {
       colorSpace = NULL;
     }
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 893540f..bce57cc 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -5431,6 +5431,7 @@ GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
   strokeOpacity = 1;
   fillOverprint = gFalse;
   strokeOverprint = gFalse;
+  overprintMode = 0;
   transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
 
   lineWidth = 1;
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index b7f94cd..c2bb1be 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -20,6 +20,7 @@
 // Copyright (C) 2009-2011 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 // Copyright (C) 2011 Andrea Canciani <ranma42 at gmail.com>
+// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -1334,6 +1335,7 @@ public:
   double getStrokeOpacity() { return strokeOpacity; }
   GBool getFillOverprint() { return fillOverprint; }
   GBool getStrokeOverprint() { return strokeOverprint; }
+  int getOverprintMode() { return overprintMode; }
   Function **getTransfer() { return transfer; }
   double getLineWidth() { return lineWidth; }
   void getLineDash(double **dash, int *length, double *start)
@@ -1404,6 +1406,7 @@ public:
   void setStrokeOpacity(double opac) { strokeOpacity = opac; }
   void setFillOverprint(GBool op) { fillOverprint = op; }
   void setStrokeOverprint(GBool op) { strokeOverprint = op; }
+  void setOverprintMode(int op) { overprintMode = op; }
   void setTransfer(Function **funcs);
   void setLineWidth(double width) { lineWidth = width; }
   void setLineDash(double *dash, int length, double start);
@@ -1484,6 +1487,7 @@ private:
   double strokeOpacity;		// stroke opacity
   GBool fillOverprint;		// fill overprint
   GBool strokeOverprint;	// stroke overprint
+  int overprintMode;		// overprint mode
   Function *transfer[4];	// transfer function (entries may be: all
 				//   NULL = identity; last three NULL =
 				//   single function; all four non-NULL =
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index c922c7a..2e3f9ae 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -177,6 +177,7 @@ public:
   virtual void updateStrokeOpacity(GfxState * /*state*/) {}
   virtual void updateFillOverprint(GfxState * /*state*/) {}
   virtual void updateStrokeOverprint(GfxState * /*state*/) {}
+  virtual void updateOverprintMode(GfxState * /*state*/) {}
   virtual void updateTransfer(GfxState * /*state*/) {}
   virtual void updateFillColorStop(GfxState * /*state*/, double /*offset*/) {}
 
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 92c7f00..e0683db 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -95,6 +95,11 @@ static inline void convertGfxColor(SplashColorPtr dest,
   GfxCMYK cmyk;
 #endif
 
+  // make gcc happy
+  color[0] = color[1] = color[2] = 0;
+#if SPLASH_CMYK
+  color[3] = 0;
+#endif
   switch (colorMode) {
     case splashModeMono1:
     case splashModeMono8:
@@ -123,18 +128,200 @@ static inline void convertGfxColor(SplashColorPtr dest,
   splashColorCopy(dest, color);
 }
 
+static inline SplashPattern *createOverprintPattern(GfxColorSpace *colorSpace, SplashColorPtr color, GBool image, Guchar tolerance = 0x01) {
+  switch (colorSpace->getMode()) {
+    case csDeviceCMYK:
+      if (image) {
+        return new SplashSolidColor(color);
+      }
+    case csSeparation:
+    case csDeviceN:
+      if (image && colorSpace->getMode() == csDeviceN) {
+        GfxDeviceNColorSpace *deviceNSpace = (GfxDeviceNColorSpace *) colorSpace;
+        GBool hasSpot = gFalse;
+        GBool hasProcess = gFalse;
+        for (int i = 0; i < deviceNSpace->getNComps(); i++) {
+          GooString *name = deviceNSpace->getColorantName(i)->upperCase();
+          if (name->cmp("CYAN") != 0 && 
+              name->cmp("MAGENTA") != 0 && 
+              name->cmp("YELLOW") != 0 && 
+              name->cmp("BLACK") != 0 && 
+              name->cmp("NONE") != 0) {
+            hasSpot = gTrue;
+          } else {
+            hasProcess = gTrue;
+          }
+        }
+        if (hasSpot && hasProcess)
+          return new SplashSolidColor(color);
+      }
+      return new SplashOverprintColor(colorSpace, color, tolerance);
+    case csIndexed:
+      return createOverprintPattern(((GfxIndexedColorSpace *) colorSpace)->getBase(), color, image);          
+    case csICCBased:
+      if (image) {
+        return createOverprintPattern(((GfxICCBasedColorSpace *) colorSpace)->getAlt(), color, gFalse, 0x05);          
+      }
+    case csDeviceGray:
+      if (image) {
+        return new SplashOverprintColor(colorSpace, color, tolerance);
+      }
+    default: // knockout
+      return new SplashSolidColor(color);
+  }
+}
+
+
+//------------------------------------------------------------------------
+// SplashOverprintColor
+//------------------------------------------------------------------------
+
+SplashOverprintColor::SplashOverprintColor(GfxColorSpace *colorSpaceA, SplashColorPtr colorA, Guchar toleranceA) {
+  splashColorCopy(color, colorA);
+  colorSpace = colorSpaceA;
+  tolerance = toleranceA;
+}
+
+SplashOverprintColor::~SplashOverprintColor() {
+}
+
+GBool SplashOverprintColor::getColor(int x, int y, SplashColorPtr c) {
+  splashColorCopy(c, color);
+  return gTrue;
+}
+
+void SplashOverprintColor::overprint(GBool op, Guchar aSrc, SplashColorPtr cSrc,
+                                     Guchar aDest, SplashColorPtr cDest,
+                                     SplashColorPtr colorResult) {
+  switch(colorSpace->getMode()) {
+    case csDeviceGray: // only in case of grayscale images
+      colorResult[0] = cDest[0];
+      colorResult[1] = cDest[1];
+      colorResult[2] = cDest[2];
+      colorResult[3] = (Guchar)(((aDest - aSrc) * cDest[3] +
+                       aSrc * cSrc[3]) / aDest);
+    break;
+    case csDeviceCMYK:
+      colorResult[0] = (cSrc[0] < tolerance && op) ?
+                       cDest[0] :
+                       (Guchar)(((aDest - aSrc) * cDest[0] + aSrc * cSrc[0]) / aDest);
+      colorResult[1] = (cSrc[1] < tolerance && op) ?
+                       cDest[1] :
+                       (Guchar)(((aDest - aSrc) * cDest[1] + aSrc * cSrc[1]) / aDest);
+      colorResult[2] = (cSrc[2] < tolerance && op) ?
+                       cDest[2] :
+                       (Guchar)(((aDest - aSrc) * cDest[2] + aSrc * cSrc[2]) / aDest);
+      colorResult[3] = (cSrc[3] < tolerance && op) ?
+                       cDest[3] :
+                       (Guchar)(((aDest - aSrc) * cDest[3] + aSrc * cSrc[3]) / aDest);
+    break;
+
+    case csSeparation:
+    {
+      GfxSeparationColorSpace *sepSpace = (GfxSeparationColorSpace *) colorSpace;
+      GooString *name = sepSpace->getName()->upperCase();
+      if (name->cmp("CYAN") == 0) {
+        colorResult[0] = (Guchar)(((aDest - aSrc) * cDest[0] +
+                         aSrc * cSrc[0]) / aDest);
+                         colorResult[1] = cDest[1];
+                         colorResult[2] = cDest[2];
+                         colorResult[3] = cDest[3];
+      } else if (name->cmp("MAGENTA") == 0) {
+        colorResult[0] = cDest[0];
+        colorResult[1] = (Guchar)(((aDest - aSrc) * cDest[1] +
+                         aSrc * cSrc[1]) / aDest);
+                         colorResult[2] = cDest[2];
+                         colorResult[3] = cDest[3];
+      } else if (name->cmp("YELLOW") == 0) {
+        colorResult[0] = cDest[0];
+        colorResult[1] = cDest[1];
+        colorResult[2] = (Guchar)(((aDest - aSrc) * cDest[2] +
+                         aSrc * cSrc[2]) / aDest);
+        colorResult[3] = cDest[3];
+      } else if (name->cmp("BLACK") == 0) {
+        colorResult[0] = cDest[0];
+        colorResult[1] = cDest[1];
+        colorResult[2] = cDest[2];
+        colorResult[3] = (Guchar)(((aDest - aSrc) * cDest[3] +
+                         aSrc * cSrc[3]) / aDest);
+      } else {
+        colorResult[0] = ((int) cDest[0] + cSrc[0]) > 0xff ? 0xff : cDest[0] + cSrc[0];
+        colorResult[1] = ((int) cDest[1] + cSrc[1]) > 0xff ? 0xff : cDest[1] + cSrc[1];
+        colorResult[2] = ((int) cDest[2] + cSrc[2]) > 0xff ? 0xff : cDest[2] + cSrc[2];
+        colorResult[3] = ((int) cDest[3] + cSrc[3]) > 0xff ? 0xff : cDest[3] + cSrc[3];
+      }
+    }
+    break;
+    case csDeviceN:
+    {
+      GfxDeviceNColorSpace *deviceNSpace = (GfxDeviceNColorSpace *) colorSpace;
+      colorResult[0] = cDest[0];
+      colorResult[1] = cDest[1];
+      colorResult[2] = cDest[2];
+      colorResult[3] = cDest[3];
+      for (int i = 0; i < deviceNSpace->getNComps(); i++) {
+        GooString *name = deviceNSpace->getColorantName(i)->upperCase();
+        if (name->cmp("CYAN") == 0) {
+          colorResult[0] = (Guchar)(((aDest - aSrc) * cDest[0] +
+                           aSrc * cSrc[0]) / aDest);
+        } else if (name->cmp("MAGENTA") == 0) {
+          colorResult[1] = (Guchar)(((aDest - aSrc) * cDest[1] +
+                           aSrc * cSrc[1]) / aDest);
+        } else if (name->cmp("YELLOW") == 0) {
+          colorResult[2] = (Guchar)(((aDest - aSrc) * cDest[2] +
+                           aSrc * cSrc[2]) / aDest);
+        } else if (name->cmp("BLACK") == 0) {
+          colorResult[3] = (Guchar)(((aDest - aSrc) * cDest[3] +
+                           aSrc * cSrc[3]) / aDest);
+        } else if (name->cmp("NONE") != 0) { 
+          colorResult[0] = (cSrc[0] < tolerance && op) ?
+                           cDest[0] :
+                           (Guchar)(((aDest - aSrc) * cDest[0] + aSrc * cSrc[0]) / aDest);
+          colorResult[1] = (cSrc[1] < tolerance && op) ?
+                           cDest[1] :
+                           (Guchar)(((aDest - aSrc) * cDest[1] + aSrc * cSrc[1]) / aDest);
+          colorResult[2] = (cSrc[2] < tolerance && op) ?
+                           cDest[2] :
+                           (Guchar)(((aDest - aSrc) * cDest[2] + aSrc * cSrc[2]) / aDest);
+          colorResult[3] = (cSrc[3] < tolerance && op) ?
+                           cDest[3] :
+                           (Guchar)(((aDest - aSrc) * cDest[3] + aSrc * cSrc[3]) / aDest);
+          break;
+        }
+      }
+    }
+    break;
+    default:
+        // default for overprint is knockout:
+        colorResult[0] = (Guchar)(((aDest - aSrc) * cDest[0] +
+                         aSrc * cSrc[0]) / aDest);
+        colorResult[1] = (Guchar)(((aDest - aSrc) * cDest[1] +
+                         aSrc * cSrc[1]) / aDest);
+        colorResult[2] = (Guchar)(((aDest - aSrc) * cDest[2] +
+                         aSrc * cSrc[2]) / aDest);
+        colorResult[3] = (Guchar)(((aDest - aSrc) * cDest[3] +
+                         aSrc * cSrc[3]) / aDest);
+  }
+}
 
 //------------------------------------------------------------------------
 // SplashGouraudPattern
 //------------------------------------------------------------------------
 SplashGouraudPattern::SplashGouraudPattern(GBool bDirectColorTranslationA,
-                                           GfxState *stateA, GfxGouraudTriangleShading *shadingA) {
+                                           GfxState *stateA, GfxGouraudTriangleShading *shadingA, SplashColorMode modeA) {
+  SplashColor defaultColor;
+  GfxColor srcColor;
   state = stateA;
   shading = shadingA;
+  mode = modeA;
   bDirectColorTranslation = bDirectColorTranslationA;
+  shadingA->getColorSpace()->getDefaultColor(&srcColor);
+  convertGfxColor(defaultColor, mode, shadingA->getColorSpace(), &srcColor);
+  opPattern = new SplashOverprintColor(shadingA->getColorSpace(), defaultColor, 0x01);
 }
 
 SplashGouraudPattern::~SplashGouraudPattern() {
+  delete opPattern;
 }
 
 void SplashGouraudPattern::getParameterizedColor(double colorinterp, SplashColorMode mode, SplashColorPtr dest) {
@@ -156,6 +343,11 @@ void SplashGouraudPattern::getParameterizedColor(double colorinterp, SplashColor
   }
 }
 
+void SplashGouraudPattern::overprint(GBool op, Guchar aSrc, SplashColorPtr cSrc,
+                                     Guchar aDest, SplashColorPtr cDest,
+                                     SplashColorPtr colorResult) {
+  opPattern->overprint(op, aSrc, cSrc, aDest, cDest, colorResult);
+}
 //------------------------------------------------------------------------
 // SplashUnivariatePattern
 //------------------------------------------------------------------------
@@ -214,6 +406,9 @@ GBool SplashUnivariatePattern::testPosition(int x, int y) {
 SplashRadialPattern::SplashRadialPattern(SplashColorMode colorModeA, GfxState *stateA, GfxRadialShading *shadingA):
   SplashUnivariatePattern(colorModeA, stateA, shadingA)
 {
+  SplashColor defaultColor;
+  GfxColor srcColor;
+
   shadingA->getCoords(&x0, &y0, &r0, &dx, &dy, &dr);
   dx -= x0;
   dy -= y0;
@@ -221,9 +416,13 @@ SplashRadialPattern::SplashRadialPattern(SplashColorMode colorModeA, GfxState *s
   a = dx*dx + dy*dy - dr*dr;
   if (fabs(a) > RADIAL_EPSILON)
     inva = 1.0 / a;
+  shadingA->getColorSpace()->getDefaultColor(&srcColor);
+  convertGfxColor(defaultColor, colorModeA, shadingA->getColorSpace(), &srcColor);
+  opPattern = new SplashOverprintColor(shadingA->getColorSpace(), defaultColor, 0x01);
 }
 
 SplashRadialPattern::~SplashRadialPattern() {
+  delete opPattern;
 }
 
 GBool SplashRadialPattern::getParameter(double xs, double ys, SplashCoord *t) {
@@ -309,6 +508,12 @@ GBool SplashRadialPattern::getParameter(double xs, double ys, SplashCoord *t) {
   return gFalse;
 }
 
+void SplashRadialPattern::overprint(GBool op, Guchar aSrc, SplashColorPtr cSrc,
+                                    Guchar aDest, SplashColorPtr cDest,
+                                    SplashColorPtr colorResult) {
+  opPattern->overprint(op, aSrc, cSrc, aDest, cDest, colorResult);
+}
+
 #undef RADIAL_EPSILON
 
 //------------------------------------------------------------------------
@@ -318,13 +523,20 @@ GBool SplashRadialPattern::getParameter(double xs, double ys, SplashCoord *t) {
 SplashAxialPattern::SplashAxialPattern(SplashColorMode colorModeA, GfxState *stateA, GfxAxialShading *shadingA):
     SplashUnivariatePattern(colorModeA, stateA, shadingA)
 {
+  SplashColor defaultColor;
+  GfxColor srcColor;
+
   shadingA->getCoords(&x0, &y0, &x1, &y1);
   dx = x1 - x0;
   dy = y1 - y0;
   mul = 1 / (dx * dx + dy * dy);
+  shadingA->getColorSpace()->getDefaultColor(&srcColor);
+  convertGfxColor(defaultColor, colorModeA, shadingA->getColorSpace(), &srcColor);
+  opPattern = new SplashOverprintColor(shadingA->getColorSpace(), defaultColor, 0x01);
 }
 
 SplashAxialPattern::~SplashAxialPattern() {
+  delete opPattern;
 }
 
 GBool SplashAxialPattern::getParameter(double xc, double yc, double *t) {
@@ -347,6 +559,12 @@ GBool SplashAxialPattern::getParameter(double xc, double yc, double *t) {
   return gTrue;
 }
 
+void SplashAxialPattern::overprint(GBool op, Guchar aSrc, SplashColorPtr cSrc,
+                                   Guchar aDest, SplashColorPtr cDest,
+                                   SplashColorPtr colorResult) {
+  opPattern->overprint(op, aSrc, cSrc, aDest, cDest, colorResult);
+}
+
 //------------------------------------------------------------------------
 
 // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
@@ -1405,7 +1623,7 @@ void SplashOutputDev::updateFillColor(GfxState *state) {
   state->getFillRGB(&rgb);
 #if SPLASH_CMYK
   state->getFillCMYK(&cmyk);
-  splash->setFillPattern(getColor(gray, &rgb, &cmyk));
+  splash->setFillPattern(getColor(state->getFillColorSpace(), gray, &rgb, &cmyk));
 #else
   splash->setFillPattern(getColor(gray, &rgb));
 #endif
@@ -1422,14 +1640,14 @@ void SplashOutputDev::updateStrokeColor(GfxState *state) {
   state->getStrokeRGB(&rgb);
 #if SPLASH_CMYK
   state->getStrokeCMYK(&cmyk);
-  splash->setStrokePattern(getColor(gray, &rgb, &cmyk));
+  splash->setStrokePattern(getColor(state->getStrokeColorSpace(), gray, &rgb, &cmyk));
 #else
   splash->setStrokePattern(getColor(gray, &rgb));
 #endif
 }
 
 #if SPLASH_CMYK
-SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb,
+SplashPattern *SplashOutputDev::getColor(GfxColorSpace *colorSpace, GfxGray gray, GfxRGB *rgb,
 					 GfxCMYK *cmyk) {
 #else
 SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
@@ -1471,7 +1689,7 @@ SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
     color[1] = colToByte(cmyk->m);
     color[2] = colToByte(cmyk->y);
     color[3] = colToByte(cmyk->k);
-    pattern = new SplashSolidColor(color);
+    pattern = createOverprintPattern(colorSpace, color, gFalse);
     break;
 #endif
   }
@@ -1491,6 +1709,18 @@ void SplashOutputDev::updateStrokeOpacity(GfxState *state) {
   splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity());
 }
 
+void SplashOutputDev::updateFillOverprint(GfxState *state) {
+  splash->setFillOverprint(state->getFillOverprint());
+}
+
+void SplashOutputDev::updateStrokeOverprint(GfxState *state) {
+  splash->setStrokeOverprint(state->getStrokeOverprint());
+}
+
+void SplashOutputDev::updateOverprintMode(GfxState *state) {
+  splash->setOverprintMode(state->getOverprintMode());
+}
+
 void SplashOutputDev::updateFont(GfxState * /*state*/) {
   needFontUpdate = gTrue;
 }
@@ -2663,12 +2893,15 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   SplashCoord mat[6];
   SplashOutImageData imgData;
   SplashColorMode srcMode;
+  SplashColor defaultColor;
+  GfxColor srcColor;
   SplashImageSource src;
   GfxGray gray;
   GfxRGB rgb;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
 #endif
+  GBool grayIndexed = gFalse;
   Guchar pix;
   int n, i;
 
@@ -2733,15 +2966,25 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
       break;
 #if SPLASH_CMYK
     case splashModeCMYK8:
+      grayIndexed = colorMap->getColorSpace()->getMode() != csDeviceGray;
       imgData.lookup = (SplashColorPtr)gmallocn(n, 4);
       for (i = 0; i < n; ++i) {
 	pix = (Guchar)i;
 	colorMap->getCMYK(&pix, &cmyk);
+	if (cmyk.c != 0 || cmyk.m != 0 || cmyk.y != 0) {
+	  grayIndexed = gFalse;
+	}
 	imgData.lookup[4*i] = colToByte(cmyk.c);
 	imgData.lookup[4*i+1] = colToByte(cmyk.m);
 	imgData.lookup[4*i+2] = colToByte(cmyk.y);
 	imgData.lookup[4*i+3] = colToByte(cmyk.k);
       }
+#ifndef USE_CMS
+	  if (colorMap->getColorSpace()->getMode() == csIndexed) {
+		  if (((GfxIndexedColorSpace *) colorMap->getColorSpace())->getBase()->getMode() == csICCBased)
+			  grayIndexed = gFalse;
+	  }
+#endif
       break;
 #endif
       break;
@@ -2754,8 +2997,12 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
     srcMode = colorMode;
   }
   src = maskColors ? &alphaImageSrc : &imageSrc;
+  colorMap->getColorSpace()->getDefaultColor(&srcColor);
+  convertGfxColor(defaultColor, srcMode, colorMap->getColorSpace(), &srcColor);
+  SplashPattern *pattern = createOverprintPattern(colorMap->getColorSpace(), defaultColor, !grayIndexed);
   splash->drawImage(src, &imgData, srcMode, maskColors ? gTrue : gFalse,
-		    width, height, mat);
+	  width, height, mat, pattern);
+  delete pattern;
   if (inlineImg) {
     while (imgData.y < height) {
       imgData.imgStr->getLine();
@@ -2913,6 +3160,8 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
     delete maskColorMap;
 
   } else {
+    SplashColor defaultColor;
+    GfxColor srcColor;
 
     //----- scale the mask image to the same size as the source image
 
@@ -3025,9 +3274,12 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
     } else {
       srcMode = colorMode;
     }
+    colorMap->getColorSpace()->getDefaultColor(&srcColor);
+    convertGfxColor(defaultColor, srcMode, colorMap->getColorSpace(), &srcColor);
+    SplashPattern *pattern = createOverprintPattern(colorMap->getColorSpace(), defaultColor, gTrue);
     splash->drawImage(&maskedImageSrc, &imgData, srcMode, gTrue,
-		      width, height, mat);
-
+		      width, height, mat, pattern);
+    delete pattern;
     delete maskBitmap;
     gfree(imgData.lookup);
     delete imgData.imgStr;
@@ -3051,6 +3303,8 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
   SplashBitmap *maskBitmap;
   Splash *maskSplash;
   SplashColor maskColor;
+  SplashColor defaultColor;
+  GfxColor srcColor;
   GfxGray gray;
   GfxRGB rgb;
 #if SPLASH_CMYK
@@ -3173,8 +3427,12 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
   } else {
     srcMode = colorMode;
   }
-  splash->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat);
 
+  colorMap->getColorSpace()->getDefaultColor(&srcColor);
+  convertGfxColor(defaultColor, srcMode, colorMap->getColorSpace(), &srcColor);
+  SplashPattern *pattern = createOverprintPattern(colorMap->getColorSpace(), defaultColor, gTrue);
+  splash->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat, pattern);
+  delete pattern;
   splash->setSoftMask(NULL);
   gfree(imgData.lookup);
   delete imgData.imgStr;
@@ -3499,31 +3757,6 @@ void SplashOutputDev::clearModRegion() {
   splash->clearModRegion();
 }
 
-void SplashOutputDev::setFillColor(int r, int g, int b) {
-  GfxRGB rgb;
-  GfxGray gray;
-#if SPLASH_CMYK
-  GfxCMYK cmyk;
-#endif
-
-  rgb.r = byteToCol(r);
-  rgb.g = byteToCol(g);
-  rgb.b = byteToCol(b);
-  gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b + 0.5);
-  if (gray > gfxColorComp1) {
-    gray = gfxColorComp1;
-  }
-#if SPLASH_CMYK
-  cmyk.c = gfxColorComp1 - rgb.r;
-  cmyk.m = gfxColorComp1 - rgb.g;
-  cmyk.y = gfxColorComp1 - rgb.b;
-  cmyk.k = 0;
-  splash->setFillPattern(getColor(gray, &rgb, &cmyk));
-#else
-  splash->setFillPattern(getColor(gray, &rgb));
-#endif
-}
-
 #if 1 //~tmp: turn off anti-aliasing temporarily
 GBool SplashOutputDev::getVectorAntialias() {
   return splash->getVectorAntialias();
@@ -3545,7 +3778,7 @@ GBool SplashOutputDev::tilingPatternFill(GfxState *state, Catalog *catalog, Obje
 					double *ptm, int paintType, Dict *resDict,
 					double *mat, double *bbox,
 					int x0, int y0, int x1, int y1,
-					double xStep, double yStep) 
+					double xStep, double yStep)
 {
   PDFRectangle box;
   Gfx *gfx;
@@ -3653,7 +3886,7 @@ GBool SplashOutputDev::tilingPatternFill(GfxState *state, Catalog *catalog, Obje
   m1.m[4] = -kx;
   m1.m[5] = -ky;
 
-  bitmap = new SplashBitmap(surface_width, surface_height, colorMode != splashModeMono1, 
+  bitmap = new SplashBitmap(surface_width, surface_height, colorMode != splashModeMono1,
                             (paintType == 1) ? colorMode : splashModeMono8, gTrue);
   memset(bitmap->getAlphaPtr(), 0, bitmap->getWidth() * bitmap->getHeight());
   if (paintType == 2) {
@@ -3723,7 +3956,7 @@ GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTria
     default:
     break;
   }
-  SplashGouraudColor *splashShading = new SplashGouraudPattern(bDirectColorTranslation, state, shading);
+  SplashGouraudColor *splashShading = new SplashGouraudPattern(bDirectColorTranslation, state, shading, colorMode);
   // restore vector antialias because we support it here
   if (shading->isParameterized()) {
     GBool vaa = getVectorAntialias();
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index 26f3ddf..e44e61c 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -51,6 +51,33 @@ struct T3GlyphStack;
 struct SplashTransparencyGroup;
 
 //------------------------------------------------------------------------
+// SplashOverprintColor
+//------------------------------------------------------------------------
+
+class SplashOverprintColor: public SplashPattern {
+public:
+  SplashOverprintColor(GfxColorSpace *colorSpace, SplashColorPtr colorA, Guchar tolerance);
+
+  virtual SplashPattern *copy() { return new SplashOverprintColor(colorSpace, color, tolerance); }
+
+  virtual ~SplashOverprintColor();
+
+  virtual GBool getColor(int x, int y, SplashColorPtr c);
+
+  virtual GBool testPosition(int x, int y) { return gFalse; }
+
+  virtual GBool isStatic() { return gTrue; }
+
+  virtual void overprint(GBool op, Guchar alphaSrc, SplashColorPtr colorSrc, 
+                         Guchar alphaDest, SplashColorPtr colorDest, SplashColorPtr colorResult);
+
+private:
+  GfxColorSpace *colorSpace;
+  SplashColor color;
+  Guchar tolerance;
+};
+
+//------------------------------------------------------------------------
 // Splash dynamic pattern
 //------------------------------------------------------------------------
 
@@ -90,18 +117,22 @@ public:
 
   virtual GBool getParameter(double xs, double ys, double *t);
 
+  virtual void overprint(GBool op, Guchar alphaSrc, SplashColorPtr colorSrc, 
+                         Guchar alphaDest, SplashColorPtr colorDest, SplashColorPtr colorResult);
+
 private:
   double x0, y0, x1, y1;
   double dx, dy, mul;
+  SplashOverprintColor *opPattern;
 };
 
 // see GfxState.h, GfxGouraudTriangleShading
 class SplashGouraudPattern: public SplashGouraudColor {
 public:
 
-  SplashGouraudPattern(GBool bDirectColorTranslation, GfxState *state, GfxGouraudTriangleShading *shading);
+  SplashGouraudPattern(GBool bDirectColorTranslation, GfxState *state, GfxGouraudTriangleShading *shading, SplashColorMode mode);
 
-  virtual SplashPattern *copy() { return new SplashGouraudPattern(bDirectColorTranslation, state, shading); }
+  virtual SplashPattern *copy() { return new SplashGouraudPattern(bDirectColorTranslation, state, shading, mode); }
 
   virtual ~SplashGouraudPattern();
 
@@ -120,10 +151,14 @@ public:
 
   virtual void getParameterizedColor(double t, SplashColorMode mode, SplashColorPtr c);
 
+  virtual void overprint(GBool op, Guchar alphaSrc, SplashColorPtr colorSrc, 
+                         Guchar alphaDest, SplashColorPtr colorDest, SplashColorPtr colorResult);
 private:
   GfxGouraudTriangleShading *shading;
   GfxState *state;
   GBool bDirectColorTranslation;
+  SplashOverprintColor *opPattern;
+  SplashColorMode mode;
 };
 
 // see GfxState.h, GfxRadialShading
@@ -138,9 +173,13 @@ public:
 
   virtual GBool getParameter(double xs, double ys, double *t);
 
+  virtual void overprint(GBool op, Guchar alphaSrc, SplashColorPtr colorSrc, 
+                         Guchar alphaDest, SplashColorPtr colorDest, SplashColorPtr colorResult);
+
 private:
   double x0, y0, r0, dx, dy, dr;
   double a, inva;
+  SplashOverprintColor *opPattern;
 };
 
 //------------------------------------------------------------------------
@@ -220,6 +259,9 @@ public:
   virtual void updateBlendMode(GfxState *state);
   virtual void updateFillOpacity(GfxState *state);
   virtual void updateStrokeOpacity(GfxState *state);
+  virtual void updateFillOverprint(GfxState *state);
+  virtual void updateStrokeOverprint(GfxState *state);
+  virtual void updateOverprintMode(GfxState *state);
 
   //----- update text state
   virtual void updateFont(GfxState *state);
@@ -327,9 +369,6 @@ public:
   // Clear the modified region.
   void clearModRegion();
 
-  // Set the Splash fill color.
-  void setFillColor(int r, int g, int b);
-
   SplashFont *getCurrentFont() { return font; }
 
 #if 1 //~tmp: turn off anti-aliasing temporarily
@@ -344,7 +383,7 @@ private:
 
   void setupScreenParams(double hDPI, double vDPI);
 #if SPLASH_CMYK
-  SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk);
+  SplashPattern *getColor(GfxColorSpace *colorSpace, GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk);
 #else
   SplashPattern *getColor(GfxGray gray, GfxRGB *rgb);
 #endif
diff --git a/splash/Splash.cc b/splash/Splash.cc
index fe7c001..e5c8096 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -103,6 +103,10 @@ struct SplashPipe {
 
   // non-isolated group correction
   int nonIsolatedGroup;
+
+  // stroke / fill operation and pattern for calculate overprint
+  GBool stroke;
+  SplashPattern *overprintPattern;
 };
 
 SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
@@ -188,7 +192,7 @@ inline void Splash::updateModY(int y) {
 inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
 			     SplashPattern *pattern, SplashColorPtr cSrc,
 			     SplashCoord aInput, GBool usesShape,
-			     GBool nonIsolatedGroup) {
+			     GBool nonIsolatedGroup, SplashPattern *opPattern, GBool strokeA) {
   pipeSetXY(pipe, x, y);
   pipe->pattern = NULL;
 
@@ -239,6 +243,8 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
   } else {
     pipe->nonIsolatedGroup = 0;
   }
+  pipe->stroke = strokeA;
+  pipe->overprintPattern = opPattern;
 }
 
 inline void Splash::pipeRun(SplashPipe *pipe) {
@@ -297,10 +303,25 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
       break;
 #if SPLASH_CMYK
     case splashModeCMYK8:
-      *pipe->destColorPtr++ = pipe->cSrc[0];
-      *pipe->destColorPtr++ = pipe->cSrc[1];
-      *pipe->destColorPtr++ = pipe->cSrc[2];
-      *pipe->destColorPtr++ = pipe->cSrc[3];
+      if (pipe->overprintPattern != NULL && 
+          ((pipe->stroke && state->strokeOverprint) ||
+          (!pipe->stroke && state->fillOverprint))) {
+        SplashColor cResult;
+        cDest[0] = pipe->destColorPtr[0];
+        cDest[1] = pipe->destColorPtr[1];
+        cDest[2] = pipe->destColorPtr[2];
+        cDest[3] = pipe->destColorPtr[3];
+        pipe->overprintPattern->overprint(state->overprintMode == 1, pipe->aSrc, pipe->cSrc, 255, cDest, cResult);
+        *pipe->destColorPtr++ = cResult[0];
+        *pipe->destColorPtr++ = cResult[1];
+        *pipe->destColorPtr++ = cResult[2];
+        *pipe->destColorPtr++ = cResult[3];
+      } else {
+        *pipe->destColorPtr++ = pipe->cSrc[0];
+        *pipe->destColorPtr++ = pipe->cSrc[1];
+        *pipe->destColorPtr++ = pipe->cSrc[2];
+        *pipe->destColorPtr++ = pipe->cSrc[3];
+      }
       break;
 #endif
     }
@@ -435,14 +456,25 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
 	cResult2 = 0;
 	cResult3 = 0;
       } else {
-	cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+	if (pipe->overprintPattern != NULL &&
+	   ((pipe->stroke && state->strokeOverprint) ||
+	   (!pipe->stroke && state->fillOverprint))) {
+	  SplashColor cResult;
+	  pipe->overprintPattern->overprint(state->overprintMode == 1, aSrc, pipe->cSrc, alpha2, cDest, cResult);
+	  cResult0 = cResult[0];
+	  cResult1 = cResult[1];
+	  cResult2 = cResult[2];
+	  cResult3 = cResult[3];
+	} else {
+	  cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
 			     aSrc * pipe->cSrc[0]) / alpha2);
-	cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
+	  cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
 			     aSrc * pipe->cSrc[1]) / alpha2);
-	cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
+	  cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
 			     aSrc * pipe->cSrc[2]) / alpha2);
-	cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
+	  cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
 			     aSrc * pipe->cSrc[3]) / alpha2);
+	}
       }
       break;
 #endif
@@ -990,6 +1022,18 @@ void Splash::setFillAlpha(SplashCoord alpha) {
   state->fillAlpha = alpha;
 }
 
+void Splash::setFillOverprint(GBool fop) {
+  state->fillOverprint = fop;
+}
+
+void Splash::setStrokeOverprint(GBool gop) {
+  state->strokeOverprint = gop;
+}
+
+void Splash::setOverprintMode(int opm) {
+  state->overprintMode = opm;
+}
+
 void Splash::setLineWidth(SplashCoord lineWidth) {
   state->lineWidth = lineWidth;
 }
@@ -1242,7 +1286,7 @@ void Splash::strokeNarrow(SplashPath *path) {
   xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse);
 
   pipeInit(&pipe, 0, 0, state->strokePattern, NULL, state->strokeAlpha,
-	   gFalse, gFalse);
+	   gFalse, gFalse, state->strokePattern, gTrue);
 
   for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
 
@@ -1615,7 +1659,7 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
       yMaxI = state->clip->getYMaxI();
     }
 
-    pipeInit(&pipe, 0, yMinI, pattern, NULL, alpha, vectorAntialias, gFalse);
+    pipeInit(&pipe, 0, yMinI, pattern, NULL, alpha, vectorAntialias, gFalse, pattern);
 
     // draw the spans
     if (vectorAntialias) {
@@ -1685,7 +1729,7 @@ SplashError Splash::xorFill(SplashPath *path, GBool eo) {
 
     origBlendFunc = state->blendFunc;
     state->blendFunc = &blendXor;
-    pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 1, gFalse, gFalse);
+    pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 1, gFalse, gFalse, state->fillPattern);
 
     // draw the spans
     for (y = yMinI; y <= yMaxI; ++y) {
@@ -1799,7 +1843,7 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
   if (noClip) {
     if (glyph->aa) {
       pipeInit(&pipe, xStart, yStart,
-               state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
+               state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse, state->fillPattern);
       for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
         pipeSetXY(&pipe, xStart, y1);
         for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
@@ -1819,7 +1863,7 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
       const int widthEight = splashCeil(glyph->w / 8.0);
 
       pipeInit(&pipe, xStart, yStart,
-               state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
+               state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse, state->fillPattern);
       for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
         pipeSetXY(&pipe, xStart, y1);
         for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
@@ -1841,7 +1885,7 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
   } else {
     if (glyph->aa) {
       pipeInit(&pipe, xStart, yStart,
-               state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
+               state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse, state->fillPattern);
       for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
         pipeSetXY(&pipe, xStart, y1);
         for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
@@ -1865,7 +1909,7 @@ void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip)
       const int widthEight = splashCeil(glyph->w / 8.0);
 
       pipeInit(&pipe, xStart, yStart,
-               state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
+               state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse, state->fillPattern);
       for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
         pipeSetXY(&pipe, xStart, y1);
         for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
@@ -2043,7 +2087,7 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
 
   // initialize the pixel pipe
   pipeInit(&pipe, 0, 0, state->fillPattern, NULL, state->fillAlpha,
-	   gTrue, gFalse);
+	   gTrue, gFalse, state->fillPattern);
   if (vectorAntialias) {
     drawAAPixelInit();
   }
@@ -2178,7 +2222,7 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
 
 SplashError Splash::drawImage(SplashImageSource src, void *srcData,
 			      SplashColorMode srcMode, GBool srcAlpha,
-			      int w, int h, SplashCoord *mat) {
+			      int w, int h, SplashCoord *mat, SplashPattern *opImagePattern) {
   SplashPipe pipe;
   GBool ok, rot;
   SplashCoord xScale, yScale, xShear, yShear, yShear1;
@@ -2357,7 +2401,7 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
   // initialize the pixel pipe
   pipeInit(&pipe, 0, 0, NULL, pix, state->fillAlpha,
 	   srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
-	   gFalse);
+	   gFalse, opImagePattern);
   if (vectorAntialias) {
     drawAAPixelInit();
   }
@@ -3277,7 +3321,7 @@ GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
   SplashPipe pipe;
   SplashColor cSrcVal;
 
-  pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha, gFalse, gFalse);
+  pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha, gFalse, gFalse, NULL, gTrue);
 
   if (vectorAntialias) {
     if (aaBuf == NULL)
@@ -3977,7 +4021,7 @@ SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox,
       yMaxI = state->clip->getYMaxI();
     }
 
-    pipeInit(&pipe, 0, yMinI, pattern, NULL, state->fillAlpha, vectorAntialias && !hasBBox, gFalse);
+    pipeInit(&pipe, 0, yMinI, pattern, NULL, state->fillAlpha, vectorAntialias && !hasBBox, gFalse, pattern);
 
     // draw the spans
     if (vectorAntialias) {
diff --git a/splash/Splash.h b/splash/Splash.h
index 43e0229..85f92ed 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -13,7 +13,7 @@
 //
 // Copyright (C) 2005 Marco Pesenti Gritti <mpg at redhat.com>
 // Copyright (C) 2007, 2011 Albert Astals Cid <aacid at kde.org>
-// Copyright (C) 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2010, 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 //
 // To see a description of the changes please see the Changelog file that
@@ -121,6 +121,9 @@ public:
   void setBlendFunc(SplashBlendFunc func);
   void setStrokeAlpha(SplashCoord alpha);
   void setFillAlpha(SplashCoord alpha);
+  void setFillOverprint(GBool fop);
+  void setStrokeOverprint(GBool sop);
+  void setOverprintMode(int opm);
   void setLineWidth(SplashCoord lineWidth);
   void setLineCap(int lineCap);
   void setLineJoin(int lineJoin);
@@ -203,7 +206,7 @@ public:
   // The matrix behaves as for fillImageMask.
   SplashError drawImage(SplashImageSource src, void *srcData,
 			SplashColorMode srcMode, GBool srcAlpha,
-			int w, int h, SplashCoord *mat);
+			int w, int h, SplashCoord *mat, SplashPattern *overprintPattern = NULL);
 
   // Composite a rectangular region from <src> onto this Splash
   // object.
@@ -262,7 +265,7 @@ private:
   void pipeInit(SplashPipe *pipe, int x, int y,
 		SplashPattern *pattern, SplashColorPtr cSrc,
 		SplashCoord aInput, GBool usesShape,
-		GBool nonIsolatedGroup);
+		GBool nonIsolatedGroup, SplashPattern *overprintPattern = NULL, GBool stroke = gFalse);
   void pipeRun(SplashPipe *pipe);
   void pipeSetXY(SplashPipe *pipe, int x, int y);
   void pipeIncX(SplashPipe *pipe);
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index 7c26e54..562fbda 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -19,6 +19,7 @@
 // Copyright (C) 2010 Harry Roberts <harry.roberts at midnight-labs.org>
 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger at googlemail.com>
 // Copyright (C) 2010 William Bader <williambader at hotmail.com>
+// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -302,6 +303,11 @@ SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in
     #endif
 
     #ifdef ENABLE_LIBJPEG
+    #ifdef SPLASH_CMYK
+    case splashFormatJpegCMYK:
+      writer = new JpegWriter(JCS_CMYK);
+      break;
+    #endif
     case splashFormatJpeg:
       writer = new JpegWriter();
       break;
@@ -329,8 +335,35 @@ SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in
 	return e;
 }
 
+#include "poppler/GfxState_helpers.h"
+
+void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) {
+  SplashColor col;
+  double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+  for (int x = 0; x < width; x++) {
+    getPixel(x, yl, col);
+    c = byteToDbl(col[0]);
+    m = byteToDbl(col[1]);
+    y = byteToDbl(col[2]);
+    k = byteToDbl(col[3]);
+    c1 = 1 - c;
+    m1 = 1 - m;
+    y1 = 1 - y;
+    k1 = 1 - k;
+    cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+    *line++ = dblToByte(clip01(r));
+    *line++ = dblToByte(clip01(g));
+    *line++ = dblToByte(clip01(b));
+  }
+}
+
 SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) {
-  if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8) {
+  if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8
+#if SPLASH_CMYK
+      && mode != splashModeCMYK8
+#endif
+     ) {
     error(-1, "unsupported SplashBitmap mode");
     return splashErrGeneric;
   }
@@ -340,6 +373,35 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int
   }
 
   switch (mode) {
+#if SPLASH_CMYK
+    case splashModeCMYK8:
+      if (writer->supportCMYK()) {
+        SplashColorPtr row;
+        unsigned char **row_pointers = new unsigned char*[height];
+        row = data;
+
+        for (int y = 0; y < height; ++y) {
+          row_pointers[y] = row;
+          row += rowSize;
+        }
+        if (!writer->writePointers(row_pointers, height)) {
+          delete[] row_pointers;
+          return splashErrGeneric;
+        }
+        delete[] row_pointers;
+      } else {
+        unsigned char *row = new unsigned char[3 * width];
+        for (int y = 0; y < height; y++) {
+          getRGBLine(y, row);
+          if (!writer->writeRow(&row)) {
+            delete[] row;
+            return splashErrGeneric;
+          }
+        }
+        delete[] row;
+      }
+    break;
+#endif
     case splashModeRGB8:
     {
       SplashColorPtr row;
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index b276a61..3336507 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -71,6 +71,7 @@ public:
   SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI);
 
   void getPixel(int x, int y, SplashColorPtr pixel);
+  void getRGBLine(int y, SplashColorPtr line);
   Guchar getAlpha(int x, int y);
 
 private:
diff --git a/splash/SplashPattern.cc b/splash/SplashPattern.cc
index b42714d..6747973 100644
--- a/splash/SplashPattern.cc
+++ b/splash/SplashPattern.cc
@@ -11,7 +11,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2010 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2010, 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -53,3 +53,17 @@ GBool SplashSolidColor::getColor(int x, int y, SplashColorPtr c) {
   splashColorCopy(c, color);
   return gTrue;
 }
+
+void SplashSolidColor::overprint(GBool op, Guchar aSrc, SplashColorPtr cSrc, 
+                                 Guchar aDest, SplashColorPtr cDest, 
+                                 SplashColorPtr colorResult) {
+  // default for overprint is knockout:
+  colorResult[0] = (Guchar)(((aDest - aSrc) * cDest[0] +
+                   aSrc * cSrc[0]) / aDest);
+  colorResult[1] = (Guchar)(((aDest - aSrc) * cDest[1] +
+                   aSrc * cSrc[1]) / aDest);
+  colorResult[2] = (Guchar)(((aDest - aSrc) * cDest[2] +
+                   aSrc * cSrc[2]) / aDest);
+  colorResult[3] = (Guchar)(((aDest - aSrc) * cDest[3] +
+                   aSrc * cSrc[3]) / aDest);
+}
diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h
index 42c1660..de1f887 100644
--- a/splash/SplashPattern.h
+++ b/splash/SplashPattern.h
@@ -52,6 +52,10 @@ public:
   // value for all pixels.
   virtual GBool isStatic() = 0;
 
+  // calculate destination color if overprint is enables
+  virtual void overprint(GBool op, Guchar alphaSrc, SplashColorPtr colorSrc, 
+                         Guchar alphaDest, SplashColorPtr colorDest, SplashColorPtr colorResult) = 0;
+
 private:
 };
 
@@ -74,6 +78,9 @@ public:
 
   virtual GBool isStatic() { return gTrue; }
 
+  virtual void overprint(GBool op, Guchar alphaSrc, SplashColorPtr colorSrc, 
+	  Guchar alphaDest, SplashColorPtr colorDest, SplashColorPtr colorResult);
+
 private:
 
   SplashColor color;
diff --git a/splash/SplashState.cc b/splash/SplashState.cc
index b1fa2f5..15b6a72 100644
--- a/splash/SplashState.cc
+++ b/splash/SplashState.cc
@@ -11,7 +11,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009, 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -71,6 +71,9 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
   softMask = NULL;
   deleteSoftMask = gFalse;
   inNonIsolatedGroup = gFalse;
+  fillOverprint = gFalse;
+  strokeOverprint = gFalse;
+  overprintMode = 0;	  
   next = NULL;
 }
 
@@ -101,6 +104,9 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
   softMask = NULL;
   deleteSoftMask = gFalse;
   inNonIsolatedGroup = gFalse;
+  fillOverprint = gFalse;
+  strokeOverprint = gFalse;
+  overprintMode = 0;	  
   next = NULL;
 }
 
@@ -131,6 +137,9 @@ SplashState::SplashState(SplashState *state) {
   softMask = state->softMask;
   deleteSoftMask = gFalse;
   inNonIsolatedGroup = state->inNonIsolatedGroup;
+  fillOverprint = state->fillOverprint;
+  strokeOverprint = state->strokeOverprint;
+  overprintMode = state->overprintMode;	  
   next = NULL;
 }
 
diff --git a/splash/SplashState.h b/splash/SplashState.h
index d0e05df..63dadc6 100644
--- a/splash/SplashState.h
+++ b/splash/SplashState.h
@@ -4,6 +4,20 @@
 //
 //========================================================================
 
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
 #ifndef SPLASHSTATE_H
 #define SPLASHSTATE_H
 
@@ -68,6 +82,11 @@ public:
   // Set the soft mask bitmap.
   void setSoftMask(SplashBitmap *softMaskA);
 
+  // Set the overprint parametes.
+  void setFillOverprint(GBool fillOverprintA) { fillOverprint = fillOverprintA; }
+  void setStrokeOverprint(GBool strokeOverprintA) { strokeOverprint = strokeOverprintA; }
+  void setOverprintMode(int overprintModeA) { overprintMode = overprintModeA; }
+
 private:
 
   SplashState(SplashState *state);
@@ -92,6 +111,9 @@ private:
   SplashBitmap *softMask;
   GBool deleteSoftMask;
   GBool inNonIsolatedGroup;
+  GBool fillOverprint;
+  GBool strokeOverprint;
+  int overprintMode;
 
   SplashState *next;		// used by Splash class
 
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h
index 273c32d..65525b1 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -13,7 +13,7 @@
 //
 // Copyright (C) 2006, 2010 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2008 Tomas Are Haavet <tomasare at gmail.com>
-// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
+// Copyright (C) 2009, 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 Stefan Thomas <thomas at eload24.com>
 // Copyright (C) 2010 William Bader <williambader at hotmail.com>
 //
@@ -162,7 +162,8 @@ typedef int SplashError;
 enum SplashImageFileFormat {
   splashFormatJpeg,
   splashFormatPng,
-  splashFormatTiff
+  splashFormatTiff,
+  splashFormatJpegCMYK
 };
 
 #endif
diff --git a/utils/pdftoppm.cc b/utils/pdftoppm.cc
index 8a7c702..0923377 100644
--- a/utils/pdftoppm.cc
+++ b/utils/pdftoppm.cc
@@ -23,6 +23,7 @@
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2010 Jonathan Liu <net147 at gmail.com>
 // Copyright (C) 2010 William Bader <williambader at hotmail.com>
+// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -71,7 +72,9 @@ static GBool mono = gFalse;
 static GBool gray = gFalse;
 static GBool png = gFalse;
 static GBool jpeg = gFalse;
+static GBool jpegcmyk = gFalse;
 static GBool tiff = gFalse;
+static GBool overprint = gFalse;
 static char enableFreeTypeStr[16] = "";
 static char antialiasStr[16] = "";
 static char vectorAntialiasStr[16] = "";
@@ -129,8 +132,16 @@ static const ArgDesc argDesc[] = {
    "generate a PNG file"},
 #endif
 #if ENABLE_LIBJPEG
-  {"-jpeg",    argFlag,     &jpeg,           0,
+  {"-jpeg",   argFlag,     &jpeg,           0,
    "generate a JPEG file"},
+#if SPLASH_CMYK
+  {"-jpegcmyk",argFlag,    &jpegcmyk,       0,
+   "generate a CMYK JPEG file"},
+#endif
+#endif
+#if SPLASH_CMYK
+  {"-overprint",argFlag,   &overprint,      0,
+   "enable overprint"},
 #endif
 #if ENABLE_LIBTIFF
   {"-tiff",    argFlag,     &tiff,           0,
@@ -191,6 +202,8 @@ static void savePageSlice(PDFDoc *doc,
       bitmap->writeImgFile(splashFormatPng, ppmFile, x_resolution, y_resolution);
     } else if (jpeg) {
       bitmap->writeImgFile(splashFormatJpeg, ppmFile, x_resolution, y_resolution);
+    } else if (jpegcmyk) {
+      bitmap->writeImgFile(splashFormatJpegCMYK, ppmFile, x_resolution, y_resolution);
     } else if (tiff) {
       bitmap->writeImgFile(splashFormatTiff, ppmFile, x_resolution, y_resolution, TiffCompressionStr);
     } else {
@@ -337,11 +350,24 @@ int main(int argc, char *argv[]) {
   }
 
   // write PPM files
-  paperColor[0] = 255;
-  paperColor[1] = 255;
-  paperColor[2] = 255;
+#if SPLASH_CMYK
+  if (jpegcmyk || overprint) {
+    paperColor[0] = 0;
+    paperColor[1] = 0;
+    paperColor[2] = 0;
+    paperColor[3] = 0;
+  } else 
+#endif
+  {
+    paperColor[0] = 255;
+    paperColor[1] = 255;
+    paperColor[2] = 255;
+  }
   splashOut = new SplashOutputDev(mono ? splashModeMono1 :
 				    gray ? splashModeMono8 :
+#if SPLASH_CMYK
+				    (jpegcmyk || overprint) ? splashModeCMYK8 :
+#endif
 				             splashModeRGB8, 4,
 				  gFalse, paperColor);
   splashOut->startDoc(doc->getXRef());
@@ -377,7 +403,7 @@ int main(int argc, char *argv[]) {
       pg_h = tmp;
     }
     if (ppmRoot != NULL) {
-      const char *ext = png ? "png" : jpeg ? "jpg" : tiff ? "tif" : mono ? "pbm" : gray ? "pgm" : "ppm";
+      const char *ext = png ? "png" : (jpeg || jpegcmyk) ? "jpg" : tiff ? "tif" : mono ? "pbm" : gray ? "pgm" : "ppm";
       if (singleFile) {
         snprintf(ppmFile, PPM_FILE_SZ, "%.*s.%s",
               PPM_FILE_SZ - 32, ppmRoot, ext);


More information about the poppler mailing list