On 29.03.2011 00:52, Albert Astals Cid wrote:
A Dilluns, 28 de març de 2011, Thomas Freitag va escriure:
Here now a first implementation of overprint in poppler.
Can you please send a patch that doesn't revert my changes in
SplashOutputDev::imageSrc ?
Sorry, I missed that. I didn't see, that "git apply" of my patch to a fresh cloned git copy changed it without telling me something. Hopefully that's all, here the new patch.

Thomas
Thanks,
   Albert
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

.


diff --git a/goo/ImgWriter.h b/goo/ImgWriter.h
index f44c85d..0795934 100644
--- a/goo/ImgWriter.h
+++ b/goo/ImgWriter.h
@@ -27,6 +27,7 @@ class ImgWriter
 		virtual bool writeRow(unsigned char **row) = 0;
 		
 		virtual bool close() = 0;
+		virtual bool supportCMYK() { return 0; }
 };
 
 #endif
diff --git a/goo/JpegWriter.cc b/goo/JpegWriter.cc
index c9b7052..8c358bb 100644
--- a/goo/JpegWriter.cc
+++ b/goo/JpegWriter.cc
@@ -27,13 +27,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 +61,24 @@ 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;
+	}
 	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 +98,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 1f7a738..5e27798 100644
--- a/goo/JpegWriter.h
+++ b/goo/JpegWriter.h
@@ -29,8 +29,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);
@@ -39,10 +39,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..b6421ba 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 099b41c..c8f28ea 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -1332,6 +1332,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)
@@ -1402,6 +1403,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);
@@ -1482,6 +1484,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 baa0ef9..ee6ada3 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,196 @@ 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 +339,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 +402,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 +412,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 +504,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 +519,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 +555,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 +1619,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 +1636,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 +1685,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 +1705,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;
 }
@@ -2664,12 +2890,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;
 
@@ -2734,15 +2963,24 @@ 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;
@@ -2755,8 +2993,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();
@@ -2914,6 +3156,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
 
@@ -3026,9 +3270,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;
@@ -3052,6 +3299,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
@@ -3174,8 +3423,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;
@@ -3503,31 +3756,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();
@@ -3549,7 +3777,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;
@@ -3662,7 +3890,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) {
@@ -3732,7 +3960,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..34def44 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -51,6 +51,35 @@ 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 +119,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 +153,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 +175,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 +261,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 +371,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 +385,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 5d65834..34bf418 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) {
 
@@ -1602,7 +1646,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) {
@@ -1672,7 +1716,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) {
@@ -1780,7 +1824,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) {
@@ -1800,7 +1844,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) {
@@ -1822,7 +1866,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) {
@@ -1846,7 +1890,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) {
@@ -2024,7 +2068,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();
   }
@@ -2159,7 +2203,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;
@@ -2338,7 +2382,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();
   }
@@ -3258,7 +3302,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)
@@ -3959,7 +4003,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 a52dc13..c937ca1 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -120,6 +120,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);
@@ -202,7 +205,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.
@@ -261,7 +264,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..3c7fb4a 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -302,6 +302,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 +334,36 @@ SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in
 	return e;
 }
 
+#include "poppler/GfxState.h"
+#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..f8a9f58 100644
--- a/splash/SplashPattern.cc
+++ b/splash/SplashPattern.cc
@@ -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..61f4172 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..85433fb 100644
--- a/splash/SplashState.cc
+++ b/splash/SplashState.cc
@@ -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..5cd08e7 100644
--- a/splash/SplashState.h
+++ b/splash/SplashState.h
@@ -68,6 +68,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 +97,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..72d41d9 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -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..dd43787 100644
--- a/utils/pdftoppm.cc
+++ b/utils/pdftoppm.cc
@@ -71,7 +71,11 @@ static GBool mono = gFalse;
 static GBool gray = gFalse;
 static GBool png = gFalse;
 static GBool jpeg = gFalse;
+static GBool jpegcmyk = gFalse;
 static GBool tiff = gFalse;
+#ifdef SPLASH_CMYK
+static GBool overprint = gFalse;
+#endif
 static char enableFreeTypeStr[16] = "";
 static char antialiasStr[16] = "";
 static char vectorAntialiasStr[16] = "";
@@ -129,8 +133,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 +203,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 +351,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 +404,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);
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to