[poppler] DeviceN support in splash

Thomas Freitag Thomas.Freitag at kabelmail.de
Sun Apr 1 22:25:36 PDT 2012


Am 30.03.2012 10:57, schrieb Thomas Freitag:
> Hi Albert!
>
> Last weekend I nearly finished the DeviceN support in splash. It runs 
> through my regtest, and there are only a few outputs I want to have a 
> deeper look into it. If You think there is time left to look into it 
> before freeze the actual version, I'll try to finish it this weekend.
This is now the final patch for DeviceN support. It runs successfully 
through my regression tests. It has only a few minor changes to the beta 
patch which are needed to solve a few regressions.

Cheers,
Thomas
>
> Here a first beta release for the support which I used to create the 
> just mailed samples.
>
> Regards,
> Thomas
>
>
>
> _______________________________________________
> poppler mailing list
> poppler at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/poppler

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/poppler/attachments/20120402/bc883c59/attachment-0001.html>
-------------- next part --------------
diff --git a/poppler/Function.cc b/poppler/Function.cc
index 25e8f74..f4ef2b0 100644
--- a/poppler/Function.cc
+++ b/poppler/Function.cc
@@ -509,6 +509,20 @@ void SampledFunction::transform(double *in, double *out) {
   }
 }
 
+GBool SampledFunction::hasDifferntResultSet(Function *func) {
+  if (func->getType() == 0) {
+    SampledFunction *compTo = (SampledFunction *) func;
+    if (compTo->getSampleNumber() != nSamples)
+      return gTrue;
+    double *compSamples = compTo->getSamples();
+    for (int i = 0; i < nSamples; i++) {
+      if (samples[i] != compSamples[i])
+        return gTrue;
+    }
+  }
+  return gFalse;
+}
+
 //------------------------------------------------------------------------
 // ExponentialFunction
 //------------------------------------------------------------------------
diff --git a/poppler/Function.h b/poppler/Function.h
index a456dfe..797397b 100644
--- a/poppler/Function.h
+++ b/poppler/Function.h
@@ -79,6 +79,7 @@ public:
   double getRangeMin(int i) { return range[i][0]; }
   double getRangeMax(int i) { return range[i][1]; }
   GBool getHasRange() { return hasRange; }
+  virtual GBool hasDifferntResultSet(Function *func) { return gFalse; }
 
   // Transform an input tuple into an output tuple.
   virtual void transform(double *in, double *out) = 0;
@@ -126,6 +127,7 @@ public:
   virtual int getType() { return 0; }
   virtual void transform(double *in, double *out);
   virtual GBool isOk() { return ok; }
+  virtual GBool hasDifferntResultSet(Function *func);
 
   int getSampleSize(int i) { return sampleSize[i]; }
   double getEncodeMin(int i) { return encode[i][0]; }
@@ -133,6 +135,7 @@ public:
   double getDecodeMin(int i) { return decode[i][0]; }
   double getDecodeMax(int i) { return decode[i][1]; }
   double *getSamples() { return samples; }
+  int getSampleNumber() { return nSamples; }
 
 private:
 
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 75c87e9..212f173 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -248,6 +248,7 @@ cmsHPROFILE GfxColorSpace::getDisplayProfile() {
 
 GfxColorSpace::GfxColorSpace() {
   overprintMask = 0x0f;
+  mapping = NULL;
 }
 
 GfxColorSpace::~GfxColorSpace() {
@@ -321,6 +322,10 @@ GfxColorSpace *GfxColorSpace::parse(Object *csObj, Gfx *gfx, int recursion) {
   return cs;
 }
 
+void GfxColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+  return;
+}
+
 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
 				     int maxImgPixel) {
   int i;
@@ -614,6 +619,12 @@ void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->k = clip01(gfxColorComp1 - color->c[0]);
 }
 
+void GfxDeviceGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  deviceN->c[3] = clip01(gfxColorComp1 - color->c[0]);
+}
+
 void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0] = 0;
 }
@@ -822,6 +833,17 @@ void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->k = k;
 }
 
+void GfxCalGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  GfxCMYK cmyk;
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  getCMYK(color, &cmyk);
+  deviceN->c[0] = cmyk.c;
+  deviceN->c[1] = cmyk.m;
+  deviceN->c[2] = cmyk.y;
+  deviceN->c[3] = cmyk.k;
+}
+
 void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0] = 0;
 }
@@ -907,6 +929,17 @@ void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->k = k;
 }
 
+void GfxDeviceRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  GfxCMYK cmyk;
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  getCMYK(color, &cmyk);
+  deviceN->c[0] = cmyk.c;
+  deviceN->c[1] = cmyk.m;
+  deviceN->c[2] = cmyk.y;
+  deviceN->c[3] = cmyk.k;
+}
+
 void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0] = 0;
   color->c[1] = 0;
@@ -1139,6 +1172,17 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->k = k;
 }
 
+void GfxCalRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  GfxCMYK cmyk;
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  getCMYK(color, &cmyk);
+  deviceN->c[0] = cmyk.c;
+  deviceN->c[1] = cmyk.m;
+  deviceN->c[2] = cmyk.y;
+  deviceN->c[3] = cmyk.k;
+}
+
 void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0] = 0;
   color->c[1] = 0;
@@ -1239,6 +1283,15 @@ void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->k = clip01(color->c[3]);
 }
 
+void GfxDeviceCMYKColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  deviceN->c[0] = clip01(color->c[0]);
+  deviceN->c[1] = clip01(color->c[1]);
+  deviceN->c[2] = clip01(color->c[2]);
+  deviceN->c[3] = clip01(color->c[3]);
+}
+
 void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0] = 0;
   color->c[1] = 0;
@@ -1465,6 +1518,17 @@ void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->k = k;
 }
 
+void GfxLabColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  GfxCMYK cmyk;
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  getCMYK(color, &cmyk);
+  deviceN->c[0] = cmyk.c;
+  deviceN->c[1] = cmyk.m;
+  deviceN->c[2] = cmyk.y;
+  deviceN->c[3] = cmyk.k;
+}
+
 void GfxLabColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0] = 0;
   if (aMin > 0) {
@@ -1870,6 +1934,17 @@ GBool GfxICCBasedColorSpace::useGetRGBLine() {
 #endif
 }
 
+void GfxICCBasedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  GfxCMYK cmyk;
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  getCMYK(color, &cmyk);
+  deviceN->c[0] = cmyk.c;
+  deviceN->c[1] = cmyk.m;
+  deviceN->c[2] = cmyk.y;
+  deviceN->c[3] = cmyk.k;
+}
+
 void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) {
   int i;
 
@@ -2082,6 +2157,12 @@ void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   base->getCMYK(mapColorToBase(color, &color2), cmyk);
 }
 
+void GfxIndexedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  GfxColor color2;
+
+  base->getDeviceN(mapColorToBase(color, &color2), deviceN);
+}
+
 void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0] = 0;
 }
@@ -2112,6 +2193,8 @@ GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA,
     overprintMask = 0x04;
   } else if (!name->cmp("Black")) {
     overprintMask = 0x08;
+  } else if (!name->cmp("All")) {
+    overprintMask = 0xffffffff;
   }
 }
 
@@ -2119,23 +2202,32 @@ GfxSeparationColorSpace::GfxSeparationColorSpace(GooString *nameA,
 						 GfxColorSpace *altA,
 						 Function *funcA,
 						 GBool nonMarkingA,
-						 Guint overprintMaskA) {
+						 Guint overprintMaskA,
+						 int *mappingA) {
   name = nameA;
   alt = altA;
   func = funcA;
   nonMarking = nonMarkingA;
   overprintMask = overprintMaskA;
+  mapping = mappingA;
 }
 
 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
   delete name;
   delete alt;
   delete func;
+  if (mapping != NULL)
+    gfree(mapping);
 }
 
 GfxColorSpace *GfxSeparationColorSpace::copy() {
+  int *mappingA = NULL;
+  if (mapping != NULL) {
+    mappingA = (int *) gmalloc(sizeof(int));
+    *mappingA = *mapping;
+  }
   return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(),
-				     nonMarking, overprintMask);
+				     nonMarking, overprintMask, mappingA);
 }
 
 //~ handle the 'All' and 'None' colorants
@@ -2222,10 +2314,75 @@ void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   alt->getCMYK(&color2, cmyk);
 }
 
+void GfxSeparationColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  if (mapping == NULL || mapping[0] == -1) {
+    GfxCMYK cmyk;
+
+    getCMYK(color, &cmyk);
+    deviceN->c[0] = cmyk.c;
+    deviceN->c[1] = cmyk.m;
+    deviceN->c[2] = cmyk.y;
+    deviceN->c[3] = cmyk.k;
+  } else {
+    deviceN->c[mapping[0]] = color->c[0];
+  }
+}
+
 void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0] = gfxColorComp1;
 }
 
+void GfxSeparationColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+  if (nonMarking)
+    return;
+  mapping = (int *)gmalloc(sizeof(int));
+  switch (overprintMask) {
+    case 0x01:
+      *mapping = 0;
+      break;
+    case 0x02:
+      *mapping = 1;
+      break;
+    case 0x04:
+      *mapping = 2;
+      break;
+    case 0x08:
+      *mapping = 3;
+      break;
+    default:
+      Guint newOverprintMask = 0x10;
+      for (int i = 0; i < separationList->getLength(); i++) {
+        GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+        if (!sepCS->getName()->cmp(name)) {
+          if (sepCS->getFunc()->hasDifferntResultSet(func)) {
+            error(errSyntaxWarning, -1,
+              "Different functions found for '{0:s}', convert immediately", name);
+            gfree(mapping);
+            mapping = NULL;
+            return;
+          }
+          *mapping = i+4;
+          overprintMask = newOverprintMask;
+          return;
+        }
+        newOverprintMask <<=1;
+      }
+      if (separationList->getLength() == maxSepComps) {
+        error(errSyntaxWarning, -1,
+	        "Too many ({0:d}) spots, convert '{1:s}' immediately", maxSepComps, name);
+        gfree(mapping);
+        mapping = NULL;
+        return;
+      }
+      *mapping = separationList->getLength() + 4;
+      separationList->append(this->copy());
+      overprintMask = newOverprintMask;
+      break;
+  }
+}
+
 //------------------------------------------------------------------------
 // GfxDeviceNColorSpace
 //------------------------------------------------------------------------
@@ -2233,14 +2390,17 @@ void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
 					   GooString **namesA,
 					   GfxColorSpace *altA,
-					   Function *funcA) {
+					   Function *funcA,
+					   GooList *sepsCSA) {
   int i;
 
   nComps = nCompsA;
   alt = altA;
   func = funcA;
+  sepsCS = sepsCSA;
   nonMarking = gTrue;
   overprintMask = 0;
+  mapping = NULL;
   for (i = 0; i < nComps; ++i) {
     names[i] = namesA[i];
     if (names[i]->cmp("None")) {
@@ -2254,6 +2414,8 @@ GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
       overprintMask |= 0x04;
     } else if (!names[i]->cmp("Black")) {
       overprintMask |= 0x08;
+    } else if (!names[i]->cmp("All")) {
+      overprintMask = 0xffffffff;
     } else {
       overprintMask = 0x0f;
     }
@@ -2264,6 +2426,8 @@ GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
 					   GooString **namesA,
 					   GfxColorSpace *altA,
 					   Function *funcA,
+					   GooList *sepsCSA,
+					   int *mappingA,
 					   GBool nonMarkingA,
 					   Guint overprintMaskA) {
   int i;
@@ -2271,6 +2435,8 @@ GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
   nComps = nCompsA;
   alt = altA;
   func = funcA;
+  sepsCS = sepsCSA;
+  mapping = mappingA;
   nonMarking = nonMarkingA;
   overprintMask = overprintMaskA;
   for (i = 0; i < nComps; ++i) {
@@ -2286,11 +2452,25 @@ GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
   }
   delete alt;
   delete func;
+  deleteGooList(sepsCS, GfxSeparationColorSpace);
+  if (mapping != NULL)
+    gfree(mapping);
 }
 
 GfxColorSpace *GfxDeviceNColorSpace::copy() {
+  int i;
+  int *mappingA = NULL;
+
+  GooList *sepsCSA = new GooList(sepsCS->getLength());
+  for (i = 0; i < sepsCS->getLength(); i++)
+    sepsCSA->append(((GfxSeparationColorSpace *) sepsCS->get(i))->copy());
+  if (mapping != NULL) {
+    mappingA = (int *)gmalloc(sizeof(int) * nComps);
+    for (i = 0; i < nComps; i++)
+      mappingA[i] = mapping[i];
+  }
   return new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(),
-				  nonMarking, overprintMask);
+				  sepsCSA, mappingA, nonMarking, overprintMask);
 }
 
 //~ handle the 'None' colorant
@@ -2302,6 +2482,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, Gfx *gfx, int recursion)
   Function *funcA;
   Object obj1, obj2;
   int i;
+  GooList *separationList = new GooList();
 
   if (arr->getLength() != 4 && arr->getLength() != 5) {
     error(errSyntaxWarning, -1, "Bad DeviceN color space");
@@ -2338,7 +2519,26 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, Gfx *gfx, int recursion)
     goto err4;
   }
   obj1.free();
-  cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA);
+  if (arr->getLength() == 5) {
+    if (!arr->get(4, &obj1)->isDict()) {
+      error(errSyntaxWarning, -1, "Bad DeviceN color space (attributes)");
+      goto err4;
+    }
+    Dict *attribs = obj1.getDict();
+    attribs->lookup("Colorants", &obj2);
+    if (obj2.isDict()) {
+      Dict *colorants = obj2.getDict();
+      for (i = 0; i < colorants->getLength(); i++) {
+        Object obj3;
+        colorants->getVal(i, &obj3);
+        separationList->append(GfxSeparationColorSpace::parse(obj3.getArray(), gfx, recursion));
+        obj3.free();
+      }
+    }
+    obj2.free();
+    obj1.free();
+  }
+  cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, separationList);
   return cs;
 
  err4:
@@ -2350,6 +2550,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, Gfx *gfx, int recursion)
  err2:
   obj1.free();
  err1:
+  delete separationList;
   return NULL;
 }
 
@@ -2398,6 +2599,24 @@ void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   alt->getCMYK(&color2, cmyk);
 }
 
+void GfxDeviceNColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  if (mapping == NULL) {
+    GfxCMYK cmyk;
+
+    getCMYK(color, &cmyk);
+    deviceN->c[0] = cmyk.c;
+    deviceN->c[1] = cmyk.m;
+    deviceN->c[2] = cmyk.y;
+    deviceN->c[3] = cmyk.k;
+  } else {
+    for (int j = 0; j < nComps; j++)
+      if (mapping[j] != -1)
+        deviceN->c[mapping[j]] = color->c[j];
+  }
+}
+
 void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) {
   int i;
 
@@ -2406,6 +2625,95 @@ void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) {
   }
 }
 
+void GfxDeviceNColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+  if (nonMarking)               // None
+    return;
+  mapping = (int *)gmalloc(sizeof(int) * nComps);
+  Guint newOverprintMask = 0;
+  for (int i = 0; i < nComps; i++) {
+    if (!names[i]->cmp("None")) {
+      mapping[i] = -1;
+    } else if (!names[i]->cmp("Cyan")) {
+      newOverprintMask |= 0x01;
+      mapping[i] = 0;
+    } else if (!names[i]->cmp("Magenta")) {
+      newOverprintMask |= 0x02;
+      mapping[i] = 1;
+    } else if (!names[i]->cmp("Yellow")) {
+      newOverprintMask |= 0x04;
+      mapping[i] = 2;
+    } else if (!names[i]->cmp("Black")) {
+      newOverprintMask |= 0x08;
+      mapping[i] = 3;
+    } else {
+      Guint startOverprintMask = 0x10;
+      GBool found = gFalse;
+      Function *sepFunc = NULL;
+      if (nComps == 1)
+        sepFunc = func;
+      else {
+        for (int k = 0; k < sepsCS->getLength(); k++) {
+          GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k);
+          if (!sepCS->getName()->cmp(names[i])) {
+            sepFunc = sepCS->getFunc();
+            break;
+          }
+        }
+      }
+      for (int j = 0; j < separationList->getLength(); j++) {
+        GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(j);
+        if (!sepCS->getName()->cmp(names[i])) {
+          if (sepFunc != NULL && sepCS->getFunc()->hasDifferntResultSet(sepFunc)) {
+            error(errSyntaxWarning, -1,
+              "Different functions found for '{0:s}', convert immediately", names[i]);
+            gfree(mapping);
+            mapping = NULL;
+            overprintMask = 0xffffffff;
+            return;
+          }
+          mapping[i] = j+4;
+          newOverprintMask |= startOverprintMask;
+          found = gTrue;
+          break;
+        }
+        startOverprintMask <<=1;
+      }
+      if (!found) {
+        if (separationList->getLength() == maxSepComps) {
+          error(errSyntaxWarning, -1,
+            "Too many ({0:d}) spots, convert '{1:s}' immediately", maxSepComps, names[i]);
+          gfree(mapping);
+          mapping = NULL;
+          overprintMask = 0xffffffff;
+          return;
+        }
+        mapping[i] = separationList->getLength() + 4;
+        newOverprintMask |= startOverprintMask;
+        if (nComps == 1)
+          separationList->append(new GfxSeparationColorSpace(names[i]->copy(),alt->copy(), func->copy()));
+        else {
+          for (int k = 0; k < sepsCS->getLength(); k++) {
+            GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k);
+            if (!sepCS->getName()->cmp(names[i])) {
+              found = gTrue;
+              separationList->append(sepCS->copy());
+              break;
+            }
+          }
+          if(!found) {
+            error(errSyntaxWarning, -1, "DeviceN has no suitable colorant");
+            gfree(mapping);
+            mapping = NULL;
+            overprintMask = 0xffffffff;
+            return;
+          }
+        }
+      }
+    }
+  }
+  overprintMask = newOverprintMask;
+}
+
 //------------------------------------------------------------------------
 // GfxPatternColorSpace
 //------------------------------------------------------------------------
@@ -2461,6 +2769,12 @@ void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
   cmyk->k = 1;
 }
 
+void GfxPatternColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+  for (int i = 0; i < gfxColorMaxComps; i++)
+    deviceN->c[i] = 0;
+  deviceN->c[3] = 1;
+}
+
 void GfxPatternColorSpace::getDefaultColor(GfxColor *color) {
   color->c[0]=0;
 }
@@ -5260,6 +5574,23 @@ void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
   }
 }
 
+void GfxImageColorMap::getDeviceN(Guchar *x, GfxColor *deviceN) {
+  GfxColor color;
+  int i;
+
+  if (colorSpace2) {
+    for (i = 0; i < nComps2; ++i) {
+      color.c[i] = lookup2[i][x[0]];
+    }
+    colorSpace2->getDeviceN(&color, deviceN);
+  } else {
+    for (i = 0; i < nComps; ++i) {
+      color.c[i] = lookup[i][x[i]];
+    }
+    colorSpace->getDeviceN(&color, deviceN);
+  }
+}
+
 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
   int maxPixel, i;
 
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 856ec3f..2fbb286 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -48,6 +48,7 @@ class GfxFont;
 class PDFRectangle;
 class GfxShading;
 class PopplerCache;
+class GooList;
 
 class Matrix {
 public:
@@ -202,11 +203,15 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray) = 0;
   virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0;
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0;
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN) = 0;
   virtual void getGrayLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getGrayLine this should not happen"); }
   virtual void getRGBLine(Guchar * /*in*/, unsigned int * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBLine (first variant) this should not happen"); }
   virtual void getRGBLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) {  error(errInternal, -1, "GfxColorSpace::getRGBLine (second variant) this should not happen"); }
   virtual void getRGBXLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) {  error(errInternal, -1, "GfxColorSpace::getRGBXLine this should not happen"); }
 
+  // create mapping for spot colorants
+  virtual void createMapping(GooList *separationList, int maxSepComps);
+
   // Does this ColorSpace support getRGBLine?
   virtual GBool useGetRGBLine() { return gFalse; }
   // Does this ColorSpace support getGrayLine?
@@ -249,6 +254,7 @@ public:
 protected:
 
   Guint overprintMask;
+  int *mapping;
 };
 
 //------------------------------------------------------------------------
@@ -266,6 +272,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
   virtual void getGrayLine(Guchar *in, Guchar *out, int length);
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
   virtual void getRGBLine(Guchar *in, Guchar *out, int length);
@@ -298,6 +305,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
 
   virtual int getNComps() { return 1; }
   virtual void getDefaultColor(GfxColor *color);
@@ -335,6 +343,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
   virtual void getGrayLine(Guchar *in, Guchar *out, int length);
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
   virtual void getRGBLine(Guchar *in, Guchar *out, int length);
@@ -367,6 +376,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
 
   virtual int getNComps() { return 3; }
   virtual void getDefaultColor(GfxColor *color);
@@ -408,6 +418,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
   virtual void getRGBLine(Guchar *, Guchar *out, int length);
   virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
@@ -437,6 +448,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
 
   virtual int getNComps() { return 3; }
   virtual void getDefaultColor(GfxColor *color);
@@ -484,6 +496,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
   virtual void getRGBLine(Guchar *in, Guchar *out, int length);
   virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
@@ -529,6 +542,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
   virtual void getRGBLine(Guchar *in, Guchar *out, int length);
   virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
@@ -546,6 +560,10 @@ public:
   int getIndexHigh() { return indexHigh; }
   Guchar *getLookup() { return lookup; }
   GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor);
+  Guint getOverprintMask() { return base->getOverprintMask(); }
+  virtual void createMapping(GooList *separationList, int maxSepComps)
+    { base->createMapping(separationList, maxSepComps); }
+
 
 private:
 
@@ -573,6 +591,9 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+  virtual void createMapping(GooList *separationList, int maxSepComps);
 
   virtual int getNComps() { return 1; }
   virtual void getDefaultColor(GfxColor *color);
@@ -588,7 +609,7 @@ private:
 
   GfxSeparationColorSpace(GooString *nameA, GfxColorSpace *altA,
 			  Function *funcA, GBool nonMarkingA,
-			  Guint overprintMaskA);
+			  Guint overprintMaskA, int *mappingA);
 
   GooString *name;		// colorant name
   GfxColorSpace *alt;		// alternate color space
@@ -604,7 +625,7 @@ class GfxDeviceNColorSpace: public GfxColorSpace {
 public:
 
   GfxDeviceNColorSpace(int nCompsA, GooString **namesA,
-		       GfxColorSpace *alt, Function *func);
+		       GfxColorSpace *alt, Function *func, GooList *sepsCS);
   virtual ~GfxDeviceNColorSpace();
   virtual GfxColorSpace *copy();
   virtual GfxColorSpaceMode getMode() { return csDeviceN; }
@@ -615,6 +636,9 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+  virtual void createMapping(GooList *separationList, int maxSepComps);
 
   virtual int getNComps() { return nComps; }
   virtual void getDefaultColor(GfxColor *color);
@@ -629,8 +653,8 @@ public:
 private:
 
   GfxDeviceNColorSpace(int nCompsA, GooString **namesA,
-		       GfxColorSpace *alt, Function *func,
-		       GBool nonMarkingA, Guint overprintMaskA);
+		       GfxColorSpace *alt, Function *func, GooList *sepsCSA,
+		       int *mappingA, GBool nonMarkingA, Guint overprintMaskA);
 
   int nComps;			// number of components
   GooString			// colorant names
@@ -638,6 +662,7 @@ private:
   GfxColorSpace *alt;		// alternate color space
   Function *func;		// tint transform (into alternate color space)
   GBool nonMarking;
+  GooList *sepsCS; // list of separation cs for spot colorants;
 };
 
 //------------------------------------------------------------------------
@@ -658,6 +683,7 @@ public:
   virtual void getGray(GfxColor *color, GfxGray *gray);
   virtual void getRGB(GfxColor *color, GfxRGB *rgb);
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+  virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
 
   virtual int getNComps() { return 0; }
   virtual void getDefaultColor(GfxColor *color);
@@ -1107,6 +1133,7 @@ public:
   void getRGBXLine(Guchar *in, Guchar *out, int length);
   void getGrayLine(Guchar *in, Guchar *out, int length);
   void getCMYK(Guchar *x, GfxCMYK *cmyk);
+  void getDeviceN(Guchar *x, GfxColor *deviceN);
   void getColor(Guchar *x, GfxColor *color);
 
 private:
@@ -1342,8 +1369,12 @@ public:
     { strokeColorSpace->getRGB(&strokeColor, rgb); }
   void getFillCMYK(GfxCMYK *cmyk)
     { fillColorSpace->getCMYK(&fillColor, cmyk); }
+  void getFillDeviceN(GfxColor *deviceN)
+    { fillColorSpace->getDeviceN(&fillColor, deviceN); }
   void getStrokeCMYK(GfxCMYK *cmyk)
     { strokeColorSpace->getCMYK(&strokeColor, cmyk); }
+  void getStrokeDeviceN(GfxColor *deviceN)
+    { strokeColorSpace->getDeviceN(&strokeColor, deviceN); }
   GfxColorSpace *getFillColorSpace() { return fillColorSpace; }
   GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; }
   GfxPattern *getFillPattern() { return fillPattern; }
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 88b53ab..a51203e 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -94,6 +94,7 @@ static inline void convertGfxColor(SplashColorPtr dest,
   GfxRGB rgb;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
 
   // make gcc happy
@@ -124,6 +125,11 @@ static inline void convertGfxColor(SplashColorPtr dest,
       color[2] = colToByte(cmyk.y);
       color[3] = colToByte(cmyk.k);
     break;
+    case splashModeDeviceN8:
+      colorSpace->getDeviceN(src, &deviceN);
+      for (int i = 0; i < SPOT_NCOMPS + 4; i++)
+        color[i] = colToByte(deviceN.c[i]);
+    break;
 #endif
   }
   splashColorCopy(dest, color);
@@ -154,6 +160,8 @@ void SplashGouraudPattern::getParameterizedColor(double colorinterp, SplashColor
 #if SPLASH_CMYK
   if (mode == splashModeCMYK8)
     colorComps=4;
+  else if (mode == splashModeDeviceN8)
+    colorComps=4 + SPOT_NCOMPS;
 #endif
 
   shading->getParameterizedColor(colorinterp, &src);
@@ -436,7 +444,7 @@ static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -460,7 +468,7 @@ static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -484,7 +492,7 @@ static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -512,7 +520,7 @@ static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -536,7 +544,7 @@ static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -561,7 +569,7 @@ static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest,
   int i, x;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -595,7 +603,7 @@ static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest,
   int i, x;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -629,7 +637,7 @@ static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -657,7 +665,7 @@ static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest,
   int i, x;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -700,7 +708,7 @@ static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -724,7 +732,7 @@ static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
 #if SPLASH_CMYK
-  if (cm == splashModeCMYK8) {
+  if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
     SplashColor rgbSrc;
     SplashColor rgbDest;
     SplashColor rgbBlend;
@@ -857,6 +865,7 @@ static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
     break;
 #if SPLASH_CMYK
   case splashModeCMYK8:
+  case splashModeDeviceN8:
     // NB: inputs have already been converted to additive mode
     setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]),
 	   &r0, &g0, &b0);
@@ -895,6 +904,7 @@ static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest,
     break;
 #if SPLASH_CMYK
   case splashModeCMYK8:
+  case splashModeDeviceN8:
     // NB: inputs have already been converted to additive mode
     setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]),
 	   &r0, &g0, &b0);
@@ -929,6 +939,7 @@ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest,
     break;
 #if SPLASH_CMYK
   case splashModeCMYK8:
+  case splashModeDeviceN8:
     // NB: inputs have already been converted to additive mode
     setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]),
 	   &r, &g, &b);
@@ -962,6 +973,7 @@ static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest,
     break;
 #if SPLASH_CMYK
   case splashModeCMYK8:
+  case splashModeDeviceN8:
     // NB: inputs have already been converted to additive mode
     setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]),
 	   &r, &g, &b);
@@ -1345,6 +1357,10 @@ void SplashOutputDev::startPage(int pageNum, GfxState *state) {
   case splashModeCMYK8:
     color[0] = color[1] = color[2] = color[3] = 0;
     break;
+  case splashModeDeviceN8:
+    for (int i = 0; i < 4 + SPOT_NCOMPS; i++)
+      color[i] = 0;
+    break;
 #endif
   }
   splash->setStrokePattern(new SplashSolidColor(color));
@@ -1383,7 +1399,9 @@ void SplashOutputDev::updateAll(GfxState *state) {
   updateFlatness(state);
   updateMiterLimit(state);
   updateStrokeAdjust(state);
+  updateFillColorSpace(state);
   updateFillColor(state);
+  updateStrokeColorSpace(state);
   updateStrokeColor(state);
   needFontUpdate = gTrue;
 }
@@ -1454,11 +1472,26 @@ void SplashOutputDev::updateStrokeAdjust(GfxState * /*state*/) {
 #endif
 }
 
+void SplashOutputDev::updateFillColorSpace(GfxState *state) {
+#if SPLASH_CMYK
+  if (colorMode == splashModeDeviceN8)
+    state->getFillColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+}
+
+void SplashOutputDev::updateStrokeColorSpace(GfxState *state) {
+#if SPLASH_CMYK
+  if (colorMode == splashModeDeviceN8)
+    state->getStrokeColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+}
+
 void SplashOutputDev::updateFillColor(GfxState *state) {
   GfxGray gray;
   GfxRGB rgb;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
 
   switch (colorMode) {
@@ -1478,6 +1511,10 @@ void SplashOutputDev::updateFillColor(GfxState *state) {
     state->getFillCMYK(&cmyk);
     splash->setFillPattern(getColor(&cmyk));
     break;
+  case splashModeDeviceN8:
+    state->getFillDeviceN(&deviceN);
+    splash->setFillPattern(getColor(&deviceN));
+    break;
 #endif
   }
 }
@@ -1487,6 +1524,7 @@ void SplashOutputDev::updateStrokeColor(GfxState *state) {
   GfxRGB rgb;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
 
   switch (colorMode) {
@@ -1506,6 +1544,10 @@ void SplashOutputDev::updateStrokeColor(GfxState *state) {
     state->getStrokeCMYK(&cmyk);
     splash->setStrokePattern(getColor(&cmyk));
     break;
+  case splashModeDeviceN8:
+    state->getStrokeDeviceN(&deviceN);
+    splash->setStrokePattern(getColor(&deviceN));
+    break;
 #endif
   }
 }
@@ -1550,6 +1592,14 @@ SplashPattern *SplashOutputDev::getColor(GfxCMYK *cmyk) {
   color[3] = colToByte(cmyk->k);
   return new SplashSolidColor(color);
 }
+
+SplashPattern *SplashOutputDev::getColor(GfxColor *deviceN) {
+  SplashColor color;
+
+  for (int i = 0; i < 4 + SPOT_NCOMPS; i++)
+    color[i] = colToByte(deviceN->c[i]);
+  return new SplashSolidColor(color);
+}
 #endif
 
 void SplashOutputDev::setOverprintMask(GfxColorSpace *colorSpace,
@@ -2624,7 +2674,7 @@ void SplashOutputDev::setSoftMaskFromImageMask(GfxState *state,
   //~ this ignores the blendingColorSpace arg
   // create the temporary bitmap
   bitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), bitmapRowPad, colorMode, gTrue,
-                            bitmapTopDown);
+    bitmapTopDown, bitmap->getSeparationList());
   splash = new Splash(bitmap, vectorAntialias,
                       transpGroup->origSplash->getScreen());
   splash->blitTransparent(transpGroup->origBitmap, 0, 0, 0, 0, bitmap->getWidth(), bitmap->getHeight());
@@ -2678,6 +2728,7 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine,
   GfxGray gray;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
   int nComps, x;
 
@@ -2726,6 +2777,13 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine,
 	*q++ = col[3];
       }
       break;
+    case splashModeDeviceN8:
+      for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+	col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    *q++ = col[cp];
+      }
+      break;
 #endif
     }
   } else {
@@ -2765,6 +2823,13 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine,
 	*q++ = colToByte(cmyk.k);
       }
       break;
+    case splashModeDeviceN8:
+      for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+	imgData->colorMap->getDeviceN(p, &deviceN);
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    *q++ = colToByte(deviceN.c[cp]);
+      }
+      break;
 #endif
     }
   }
@@ -2782,6 +2847,7 @@ GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine,
   GfxGray gray;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
   Guchar alpha;
   int nComps, x, i;
@@ -2834,6 +2900,11 @@ GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine,
 	*q++ = col[2];
 	*q++ = col[3];
 	break;
+    case splashModeDeviceN8:
+	col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+        for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          *q++ = col[cp];
+      break;
 #endif
       }
       *aq++ = alpha;
@@ -2861,6 +2932,11 @@ GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine,
 	*q++ = colToByte(cmyk.y);
 	*q++ = colToByte(cmyk.k);
 	break;
+    case splashModeDeviceN8:
+	imgData->colorMap->getDeviceN(p, &deviceN);
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    *q++ = colToByte(deviceN.c[cp]);
+	break;
 #endif
       }
       *aq++ = alpha;
@@ -2937,7 +3013,7 @@ GBool SplashOutputDev::tilingBitmapSrc(void *data, SplashColorPtr colorLine,
         imgData->pattern->getColor(x, imgData->y, pat);
         for (int i = 0; i < splashColorModeNComps[imgData->colorMode]; ++i) {
 #if SPLASH_CMYK
-          if (imgData->colorMode == splashModeCMYK8)
+          if (imgData->colorMode == splashModeCMYK8 || imgData->colorMode == splashModeDeviceN8)
             dest[i] = div255(pat[i] * (255 - col[0]));
           else
 #endif
@@ -2978,6 +3054,7 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
 #if SPLASH_CMYK
   GfxCMYK cmyk;
   GBool grayIndexed = gFalse;
+  GfxColor deviceN;
 #endif
   Guchar pix;
   int n, i;
@@ -3057,6 +3134,21 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
 	imgData.lookup[4*i+3] = colToByte(cmyk.k);
       }
       break;
+    case splashModeDeviceN8:
+      colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+      grayIndexed = colorMap->getColorSpace()->getMode() != csDeviceGray;
+      imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+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;
+        }
+        colorMap->getDeviceN(&pix, &deviceN);
+        for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          imgData.lookup[(SPOT_NCOMPS+4)*i +cp] = colToByte(deviceN.c[cp]);
+      }
+      break;
 #endif
     }
   }
@@ -3107,6 +3199,7 @@ GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine,
   GfxGray gray;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
   Guchar alpha;
   Guchar *maskPtr;
@@ -3161,6 +3254,11 @@ GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine,
 	*q++ = col[2];
 	*q++ = col[3];
 	break;
+      case splashModeDeviceN8:
+	col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    *q++ = col[cp];
+	break;
 #endif
       }
       *aq++ = alpha;
@@ -3188,6 +3286,11 @@ GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine,
 	*q++ = colToByte(cmyk.y);
 	*q++ = colToByte(cmyk.k);
 	break;
+      case splashModeDeviceN8:
+	imgData->colorMap->getDeviceN(p, &deviceN);
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    *q++ = colToByte(deviceN.c[cp]);
+	break;
 #endif
       }
       *aq++ = alpha;
@@ -3219,10 +3322,14 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
   GfxRGB rgb;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
   Guchar pix;
   int n, i;
 
+#if SPLASH_CMYK
+  colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
   setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
 		   state->getOverprintMode(), NULL);
 
@@ -3344,6 +3451,15 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
 	  imgData.lookup[4*i+3] = colToByte(cmyk.k);
 	}
 	break;
+      case splashModeDeviceN8:
+	imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4);
+	for (i = 0; i < n; ++i) {
+	  pix = (Guchar)i;
+	  colorMap->getDeviceN(&pix, &deviceN);
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      imgData.lookup[(SPOT_NCOMPS+4)*i + cp] = colToByte(deviceN.c[cp]);
+	}
+	break;
 #endif
       }
     }
@@ -3382,10 +3498,14 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
   GfxRGB rgb;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
   Guchar pix;
   int n, i;
 
+#if SPLASH_CMYK
+  colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
   setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
 		   state->getOverprintMode(), NULL);
 
@@ -3495,6 +3615,17 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
       }
       break;
 #endif
+#if SPLASH_CMYK
+    case splashModeDeviceN8:
+      imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4);
+      for (i = 0; i < n; ++i) {
+	pix = (Guchar)i;
+	colorMap->getDeviceN(&pix, &deviceN);
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    imgData.lookup[(SPOT_NCOMPS+4)*i + cp] = colToByte(deviceN.c[cp]);
+      }
+      break;
+#endif
     }
   }
 
@@ -3623,7 +3754,7 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
 
   // create the temporary bitmap
   bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
-			    bitmapTopDown);
+          bitmapTopDown, bitmap->getSeparationList());
   splash = new Splash(bitmap, vectorAntialias,
 		      transpGroup->origSplash->getScreen());
   splash->setMinLineWidth(globalParams->getMinLineWidth());
@@ -3701,6 +3832,7 @@ void SplashOutputDev::setSoftMask(GfxState *state, double *bbox,
   GfxRGB rgb;
 #if SPLASH_CMYK
   GfxCMYK cmyk;
+  GfxColor deviceN;
 #endif
   double lum, lum2;
   int tx, ty, x, y;
@@ -3744,6 +3876,12 @@ void SplashOutputDev::setSoftMask(GfxState *state, double *bbox,
 	color[3] = colToByte(cmyk.k);
 	tSplash->compositeBackground(color);
 	break;
+      case splashModeDeviceN8:
+	transpGroupStack->blendingColorSpace->getDeviceN(backdropColor, &deviceN);
+  for (int cp=0; cp < SPOT_NCOMPS+4; cp++)
+    color[cp] = colToByte(deviceN.c[cp]);
+	tSplash->compositeBackground(color);
+	break;
 #endif
       }
       delete tSplash;
@@ -3785,6 +3923,7 @@ void SplashOutputDev::setSoftMask(GfxState *state, double *bbox,
 	    break;
 #if SPLASH_CMYK
 	  case splashModeCMYK8:
+    case splashModeDeviceN8:
 	    lum = (1 - color[3] / 255.0)
 	          - (0.3 / 255.0) * color[0]
 	          - (0.59 / 255.0) * color[1]
@@ -3983,7 +4122,9 @@ GBool SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *ca
   memset(bitmap->getAlphaPtr(), 0, bitmap->getWidth() * bitmap->getHeight());
   if (paintType == 2) {
 #if SPLASH_CMYK
-    memset(bitmap->getDataPtr(), (colorMode == splashModeCMYK8) ? 0x00 : 0xFF, bitmap->getRowSize() * bitmap->getHeight());
+    memset(bitmap->getDataPtr(), 
+      (colorMode == splashModeCMYK8 || colorMode == splashModeDeviceN8) ? 0x00 : 0xFF, 
+      bitmap->getRowSize() * bitmap->getHeight());
 #else
     memset(bitmap->getDataPtr(), 0xFF, bitmap->getRowSize() * bitmap->getHeight());
 #endif
@@ -4043,7 +4184,8 @@ GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTria
     break;
 #if SPLASH_CMYK
     case splashModeCMYK8:
-      bDirectColorTranslation = (shadingMode == csDeviceCMYK);
+    case splashModeDeviceN8:
+      bDirectColorTranslation = (shadingMode == csDeviceCMYK || shadingMode == csDeviceN);
     break;
 #endif
     default:
@@ -4113,6 +4255,9 @@ GBool SplashOutputDev::univariateShadedFill(GfxState *state, SplashUnivariatePat
   state->closePath();
   path = convertPath(state, state->getPath(), gTrue);
 
+#if SPLASH_CMYK
+  pattern->getShading()->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
   setOverprintMask(pattern->getShading()->getColorSpace(), state->getFillOverprint(),
 		   state->getOverprintMode(), state->getFillColor());
   retVal = (splash->shadedFill(path, pattern->getShading()->getHasBBox(), pattern) == splashOk);
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index 95a7f65..e3b0ee8 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -215,6 +215,8 @@ public:
   virtual void updateMiterLimit(GfxState *state);
   virtual void updateLineWidth(GfxState *state);
   virtual void updateStrokeAdjust(GfxState *state);
+  virtual void updateFillColorSpace(GfxState *state);
+  virtual void updateStrokeColorSpace(GfxState *state);
   virtual void updateFillColor(GfxState *state);
   virtual void updateStrokeColor(GfxState *state);
   virtual void updateBlendMode(GfxState *state);
@@ -361,6 +363,7 @@ private:
   SplashPattern *getColor(GfxRGB *rgb);
 #if SPLASH_CMYK
   SplashPattern *getColor(GfxCMYK *cmyk);
+  SplashPattern *getColor(GfxColor *deviceN);
 #endif
   void setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag,
 			int overprintMode, GfxColor *singleColor, GBool grayIndexed = gFalse);
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 76a80f7..fc3514c 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -35,6 +35,7 @@
 #include <math.h>
 #include "goo/gmem.h"
 #include "goo/GooLikely.h"
+#include "goo/GooList.h"
 #include "poppler/Error.h"
 #include "SplashErrorCodes.h"
 #include "SplashMath.h"
@@ -165,7 +166,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
   splashPipeResultColorNoAlphaBlendRGB
 #if SPLASH_CMYK
   ,
-  splashPipeResultColorNoAlphaBlendCMYK
+  splashPipeResultColorNoAlphaBlendCMYK,
+  splashPipeResultColorNoAlphaBlendDeviceN
 #endif
 };
 
@@ -177,7 +179,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = {
   splashPipeResultColorAlphaNoBlendRGB
 #if SPLASH_CMYK
   ,
-  splashPipeResultColorAlphaNoBlendCMYK
+  splashPipeResultColorAlphaNoBlendCMYK,
+  splashPipeResultColorAlphaNoBlendDeviceN
 #endif
 };
 
@@ -189,7 +192,8 @@ SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = {
   splashPipeResultColorAlphaBlendRGB
 #if SPLASH_CMYK
   ,
-  splashPipeResultColorAlphaBlendCMYK
+  splashPipeResultColorAlphaBlendCMYK,
+  splashPipeResultColorAlphaBlendDeviceN
 #endif
 };
 
@@ -297,6 +301,8 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
 #if SPLASH_CMYK
     } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
       pipe->run = &Splash::pipeRunSimpleCMYK8;
+    } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunSimpleDeviceN8;
 #endif
     }
   } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
@@ -316,6 +322,8 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
 #if SPLASH_CMYK
     } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
       pipe->run = &Splash::pipeRunAACMYK8;
+    } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunAADeviceN8;
 #endif
     }
   }
@@ -330,6 +338,8 @@ void Splash::pipeRun(SplashPipe *pipe) {
   int t;
 #if SPLASH_CMYK
   SplashColor cSrc2, cDest2;
+  int cp, mask;
+  Guchar cResult[SPOT_NCOMPS+4];
 #endif
 
   //----- source color
@@ -405,6 +415,16 @@ void Splash::pipeRun(SplashPipe *pipe) {
       }
       pipe->destColorPtr += 4;
       break;
+    case splashModeDeviceN8:
+      mask = 1;
+      for (cp = 0; cp < SPOT_NCOMPS + 4; cp ++) {
+        if (state->overprintMask & mask) {
+          pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]];
+        }
+        mask <<= 1;
+      }
+      pipe->destColorPtr += (SPOT_NCOMPS+4);
+      break;
 #endif
     }
     if (pipe->destAlphaPtr) {
@@ -445,6 +465,10 @@ void Splash::pipeRun(SplashPipe *pipe) {
       cDest[2] = pipe->destColorPtr[2];
       cDest[3] = pipe->destColorPtr[3];
       break;
+    case splashModeDeviceN8:
+      for (cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+        cDest[cp] = pipe->destColorPtr[cp];
+      break;
 #endif
     }
     if (pipe->destAlphaPtr) {
@@ -482,6 +506,10 @@ void Splash::pipeRun(SplashPipe *pipe) {
 	t = (aDest * 255) / pipe->shape - aDest;
 	switch (bitmap->mode) {
 #if SPLASH_CMYK
+	case splashModeDeviceN8:
+	  for (cp = 4; cp < SPOT_NCOMPS + 4; cp++)
+	    cSrcNonIso[cp] = clip255(pipe->cSrc[cp] +
+				  ((pipe->cSrc[cp] - cDest[cp]) * t) / 255);
 	case splashModeCMYK8:
 	  cSrcNonIso[3] = clip255(pipe->cSrc[3] +
 				  ((pipe->cSrc[3] - cDest[3]) * t) / 255);
@@ -509,7 +537,7 @@ void Splash::pipeRun(SplashPipe *pipe) {
 
     if (state->blendFunc) {
 #if SPLASH_CMYK
-      if (bitmap->mode == splashModeCMYK8) {
+      if (bitmap->mode == splashModeCMYK8 || bitmap->mode == splashModeDeviceN8) {
 	// convert colors to additive
 	cSrc2[0] = 0xff - cSrc[0];
 	cSrc2[1] = 0xff - cSrc[1];
@@ -578,6 +606,11 @@ void Splash::pipeRun(SplashPipe *pipe) {
       cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] +
 					     aDest * cBlend[3])];
       break;
+    case splashPipeResultColorNoAlphaBlendDeviceN:
+      for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+        cResult[cp] = state->deviceNTransfer[cp][div255((255 - aDest) * cSrc[cp] +
+					     aDest * cBlend[cp])];
+      break;
 #endif
 
     case splashPipeResultColorAlphaNoBlendMono:
@@ -620,6 +653,16 @@ void Splash::pipeRun(SplashPipe *pipe) {
 					 aSrc * cSrc[3]) / alphaI];
       }
       break;
+    case splashPipeResultColorAlphaNoBlendDeviceN:
+      if (alphaI == 0) {
+        for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          cResult[cp] = 0;
+      } else {
+        for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] +
+					 aSrc * cSrc[cp]) / alphaI];
+      }
+      break;
 #endif
 
     case splashPipeResultColorAlphaBlendMono:
@@ -678,6 +721,18 @@ void Splash::pipeRun(SplashPipe *pipe) {
 					alphaI];
       }
       break;
+    case splashPipeResultColorAlphaBlendDeviceN:
+      if (alphaI == 0) {
+        for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          cResult[cp] = 0;
+      } else {
+        for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] +
+            aSrc * ((255 - alphaIm1) * cSrc[cp] +
+						alphaIm1 * cBlend[cp]) / 255) /
+					  alphaI];
+      }
+      break;
 #endif
     }
 
@@ -738,6 +793,16 @@ void Splash::pipeRun(SplashPipe *pipe) {
       }
       pipe->destColorPtr += 4;
       break;
+    case splashModeDeviceN8:
+      mask = 1;
+      for (cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+        if (state->overprintMask & mask) {
+          pipe->destColorPtr[cp] = cResult[cp];
+        }
+        mask <<=1;
+      }
+      pipe->destColorPtr += (SPOT_NCOMPS+4);
+      break;
 #endif
     }
     if (pipe->destAlphaPtr) {
@@ -852,8 +917,25 @@ void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe) {
 
   ++pipe->x;
 }
-#endif
 
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleDeviceN8(SplashPipe *pipe) {
+  //----- write destination pixel
+  int mask = 1;
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+    if (state->overprintMask & mask) {
+      pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]];
+    }
+    mask <<=1;
+  }
+  pipe->destColorPtr += (SPOT_NCOMPS+4);
+  *pipe->destAlphaPtr++ = 255;
+
+  ++pipe->x;
+}
+#endif
 
 // special case:
 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
@@ -1133,6 +1215,53 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe) {
 
   ++pipe->x;
 }
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr
+void Splash::pipeRunAADeviceN8(SplashPipe *pipe) {
+  Guchar aSrc, aDest, alpha2, aResult;
+  SplashColor cDest;
+  Guchar cResult[SPOT_NCOMPS+4];
+  int cp, mask;
+
+  //----- read destination pixel
+  for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+    cDest[cp] = pipe->destColorPtr[cp];
+  aDest = *pipe->destAlphaPtr;
+
+  //----- source alpha
+  aSrc = div255(pipe->aInput * pipe->shape);
+
+  //----- result alpha and non-isolated group element correction
+  aResult = aSrc + aDest - div255(aSrc * aDest);
+  alpha2 = aResult;
+
+  //----- result color
+  if (alpha2 == 0) {
+    for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+      cResult[cp] = 0;
+  } else {
+    for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+      cResult[cp] = state->deviceNTransfer[cp][(Guchar)(((alpha2 - aSrc) * cDest[cp] +
+					      aSrc * pipe->cSrc[cp]) / alpha2)];
+  }
+
+  //----- write destination pixel
+  mask = 1;
+  for (cp=0; cp < SPOT_NCOMPS+4; cp++) {
+    if (state->overprintMask & mask) {
+      pipe->destColorPtr[cp] = cResult[cp];
+    }
+    mask <<= 1;
+  }
+  pipe->destColorPtr += (SPOT_NCOMPS+4);
+  *pipe->destAlphaPtr++ = aResult;
+
+  ++pipe->x;
+}
 #endif
 
 inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
@@ -1161,6 +1290,9 @@ inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
   case splashModeCMYK8:
     pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
     break;
+  case splashModeDeviceN8:
+    pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (SPOT_NCOMPS + 4) * x];
+    break;
 #endif
   }
   if (bitmap->alpha) {
@@ -1203,6 +1335,9 @@ inline void Splash::pipeIncX(SplashPipe *pipe) {
   case splashModeCMYK8:
     pipe->destColorPtr += 4;
     break;
+  case splashModeDeviceN8:
+    pipe->destColorPtr += (SPOT_NCOMPS+4);
+    break;
 #endif
   }
   if (pipe->destAlphaPtr) {
@@ -1782,6 +1917,17 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) {
       }
     }
     break;
+  case splashModeDeviceN8:
+    row = bitmap->data;
+    for (y = 0; y < bitmap->height; ++y) {
+      p = row;
+      for (x = 0; x < bitmap->width; ++x) {
+        for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          *p++ = color[cp];
+      }
+      row += bitmap->rowSize;
+    }
+    break;
 #endif
   }
 
@@ -3403,6 +3549,10 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData,
     ok = srcMode == splashModeCMYK8;
     nComps = 4;
     break;
+  case splashModeDeviceN8:
+    ok = srcMode == splashModeDeviceN8;
+    nComps = SPOT_NCOMPS+4;
+    break;
 #endif
   default:
     ok = gFalse;
@@ -3789,7 +3939,7 @@ SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData,
 				 int scaledWidth, int scaledHeight) {
   SplashBitmap *dest;
 
-  dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha);
+  dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, gTrue, bitmap->getSeparationList());
   if (scaledHeight < srcHeight) {
     if (scaledWidth < srcWidth) {
       scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha,
@@ -3820,6 +3970,7 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
   Guint pix0, pix1, pix2;
 #if SPLASH_CMYK
   Guint pix3;
+  Guint pix[SPOT_NCOMPS+4], cp;
 #endif
   Guint alpha;
   Guchar *destPtr, *destAlphaPtr;
@@ -3999,6 +4150,25 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
 	*destPtr++ = (Guchar)pix2;
 	*destPtr++ = (Guchar)pix3;
 	break;
+      case splashModeDeviceN8:
+
+	// compute the final pixel
+  for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    pix[cp] = 0;
+	for (i = 0; i < xStep; ++i) {
+    for (cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+      pix[cp] += pixBuf[xx + cp];
+    }
+    xx += (SPOT_NCOMPS+4);
+	}
+	// pix / xStep * yStep
+  for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    pix[cp] = (pix[cp] * d) >> 23;
+
+	// store the pixel
+  for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    *destPtr++ = (Guchar)pix[cp];
+	break;
 #endif
 
 
@@ -4150,6 +4320,12 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
 	  *destPtr++ = (Guchar)pix[3];
 	}
 	break;
+      case splashModeDeviceN8:
+	for (i = 0; i < xStep; ++i) {
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      *destPtr++ = (Guchar)pix[cp];
+	}
+	break;
 #endif
       }
 
@@ -4293,6 +4469,13 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
 	  *destPtr++ = (Guchar)pix[3];
 	}
 	break;
+      case splashModeDeviceN8:
+	for (i = 0; i < yStep; ++i) {
+	  destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      *destPtr++ = (Guchar)pix[cp];
+	}
+	break;
 #endif
       }
 
@@ -4441,6 +4624,15 @@ void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
 	  }
 	}
 	break;
+      case splashModeDeviceN8:
+	for (i = 0; i < yStep; ++i) {
+	  for (j = 0; j < xStep; ++j) {
+	    destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+      for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+        *destPtr++ = (Guchar)pix[cp];
+	  }
+	}
+	break;
 #endif
       }
 
@@ -4662,6 +4854,10 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
     return splashErrModeMismatch;
   }
 
+  if(src->getSeparationList()->getLength() > bitmap->getSeparationList()->getLength()) {
+    for (x = bitmap->getSeparationList()->getLength(); x < src->getSeparationList()->getLength(); x++)
+      bitmap->getSeparationList()->append(((GfxSeparationColorSpace *)src->getSeparationList()->get(x))->copy());
+  }
   if (src->alpha) {
     pipeInit(&pipe, xDest, yDest, NULL, pixel,
 	     (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated);
@@ -4743,6 +4939,7 @@ void Splash::compositeBackground(SplashColorPtr color) {
   Guchar alpha, alpha1, c, color0, color1, color2;
 #if SPLASH_CMYK
   Guchar color3;
+  Guchar colorsp[SPOT_NCOMPS+4], cp;
 #endif
   int x, y, mask;
 
@@ -4872,6 +5069,29 @@ void Splash::compositeBackground(SplashColorPtr color) {
       }
     }
     break;
+  case splashModeDeviceN8:
+    for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      colorsp[cp] = color[cp];
+    for (y = 0; y < bitmap->height; ++y) {
+      p = &bitmap->data[y * bitmap->rowSize];
+      q = &bitmap->alpha[y * bitmap->width];
+      for (x = 0; x < bitmap->width; ++x) {
+	alpha = *q++;
+	if (alpha == 0)
+	{
+    for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      p[cp] = colorsp[cp];
+	}
+	else if (alpha != 255)
+	{
+	  alpha1 = 255 - alpha;
+    for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      p[cp] = div255(alpha1 * colorsp[cp] + alpha * p[cp]);
+	}
+	p += (SPOT_NCOMPS+4);
+      }
+    }
+    break;
 #endif
   }
   memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
@@ -4931,6 +5151,9 @@ GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
     case splashModeCMYK8:
       colorComps=4;
     break;
+    case splashModeDeviceN8:
+      colorComps=SPOT_NCOMPS+4;
+    break;
 #endif
   }
 
@@ -5269,6 +5492,16 @@ SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
       }
     }
     break;
+  case splashModeDeviceN8:
+    for (y = 0; y < h; ++y) {
+      p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
+      sp = &src->data[(ySrc + y) * bitmap->rowSize + 4 * xSrc];
+      for (x = 0; x < w; ++x) {
+        for (int cp=0; cp < SPOT_NCOMPS+4; cp++)
+          *p++ = *sp++;
+      }
+    }
+    break;
 #endif
   }
 
diff --git a/splash/Splash.h b/splash/Splash.h
index 53bfa81..60d4fb2 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -60,6 +60,7 @@ typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine,
 enum SplashPipeResultColorCtrl {
 #if SPLASH_CMYK
   splashPipeResultColorNoAlphaBlendCMYK,
+  splashPipeResultColorNoAlphaBlendDeviceN,
 #endif
   splashPipeResultColorNoAlphaBlendRGB,
   splashPipeResultColorNoAlphaBlendMono,
@@ -67,12 +68,14 @@ enum SplashPipeResultColorCtrl {
   splashPipeResultColorAlphaNoBlendRGB,
 #if SPLASH_CMYK
   splashPipeResultColorAlphaNoBlendCMYK,
+  splashPipeResultColorAlphaNoBlendDeviceN,
 #endif
   splashPipeResultColorAlphaBlendMono,
   splashPipeResultColorAlphaBlendRGB
 #if SPLASH_CMYK
   ,
-  splashPipeResultColorAlphaBlendCMYK
+  splashPipeResultColorAlphaBlendCMYK,
+  splashPipeResultColorAlphaBlendDeviceN
 #endif
 };
 
@@ -283,6 +286,7 @@ private:
   void pipeRunSimpleBGR8(SplashPipe *pipe);
 #if SPLASH_CMYK
   void pipeRunSimpleCMYK8(SplashPipe *pipe);
+  void pipeRunSimpleDeviceN8(SplashPipe *pipe);
 #endif
   void pipeRunAAMono1(SplashPipe *pipe);
   void pipeRunAAMono8(SplashPipe *pipe);
@@ -291,6 +295,7 @@ private:
   void pipeRunAABGR8(SplashPipe *pipe);
 #if SPLASH_CMYK
   void pipeRunAACMYK8(SplashPipe *pipe);
+  void pipeRunAADeviceN8(SplashPipe *pipe);
 #endif
   void pipeSetXY(SplashPipe *pipe, int x, int y);
   void pipeIncX(SplashPipe *pipe);
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index ab5176e..f692fd3 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -43,6 +43,7 @@
 #include "goo/PNGWriter.h"
 #include "goo/TiffWriter.h"
 #include "goo/ImgWriter.h"
+#include "goo/GooList.h"
 
 //------------------------------------------------------------------------
 // SplashBitmap
@@ -50,7 +51,7 @@
 
 SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
 			   SplashColorMode modeA, GBool alphaA,
-			   GBool topDown) {
+			   GBool topDown, GooList *separationListA) {
   width = widthA;
   height = heightA;
   mode = modeA;
@@ -93,6 +94,13 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
       rowSize = -1;
     }
     break;
+  case splashModeDeviceN8:
+    if (width > 0 && width <= INT_MAX / 4) {
+      rowSize = width * (SPOT_NCOMPS + 4);
+    } else {
+      rowSize = -1;
+    }
+    break;
 #endif
   }
   if (rowSize > 0) {
@@ -109,6 +117,10 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
   } else {
     alpha = NULL;
   }
+  separationList = new GooList();
+  if (separationListA != NULL)
+    for (int i = 0; i < separationListA->getLength(); i++)
+      separationList->append(((GfxSeparationColorSpace *) separationListA->get(i))->copy());
 }
 
 SplashBitmap::~SplashBitmap() {
@@ -120,6 +132,7 @@ SplashBitmap::~SplashBitmap() {
     }
   }
   gfree(alpha);
+  deleteGooList(separationList, GfxSeparationColorSpace);
 }
 
 
@@ -208,6 +221,7 @@ SplashError SplashBitmap::writePNMFile(FILE *f) {
 
 #if SPLASH_CMYK
   case splashModeCMYK8:
+  case splashModeDeviceN8:
     // PNM doesn't support CMYK
     error(errInternal, -1, "unsupported SplashBitmap mode");
     return splashErrGeneric;
@@ -274,6 +288,11 @@ void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
     pixel[2] = p[2];
     pixel[3] = p[3];
     break;
+  case splashModeDeviceN8:
+    p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x];
+    for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+      pixel[cp] = p[cp];
+    break;
 #endif
   }
 }
@@ -360,6 +379,31 @@ void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) {
     m = byteToDbl(col[1]);
     y = byteToDbl(col[2]);
     k = byteToDbl(col[3]);
+#if SPLASH_CMYK
+    if (separationList->getLength() > 0) {
+      for (int i = 0; i < separationList->getLength(); i++) {
+        if (col[i+4] > 0) {
+          GfxCMYK cmyk;
+          GfxColor input;
+          input.c[0] = byteToCol(col[i+4]);
+          GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+          sepCS->getCMYK(&input, &cmyk);
+          col[0] = colToByte(cmyk.c);
+          col[1] = colToByte(cmyk.m);
+          col[2] = colToByte(cmyk.y);
+          col[3] = colToByte(cmyk.k);
+          c += byteToDbl(col[0]);
+          m += byteToDbl(col[1]);
+          y += byteToDbl(col[2]);
+          k += byteToDbl(col[3]);
+        }
+      }
+      if (c > 1) c = 1;
+      if (m > 1) m = 1;
+      if (y > 1) y = 1;
+      if (k > 1) k = 1;
+    }
+#endif
     c1 = 1 - c;
     m1 = 1 - m;
     y1 = 1 - y;
@@ -371,10 +415,52 @@ void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) {
   }
 }
 
+#if SPLASH_CMYK
+void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) {
+  SplashColor col;
+
+  for (int x = 0; x < width; x++) {
+    getPixel(x, yl, col);
+    if (separationList->getLength() > 0) {
+      double c, m, y, k;
+      c = byteToDbl(col[0]);
+      m = byteToDbl(col[1]);
+      y = byteToDbl(col[2]);
+      k = byteToDbl(col[3]);
+      for (int i = 0; i < separationList->getLength(); i++) {
+        if (col[i+4] > 0) {
+          GfxCMYK cmyk;
+          GfxColor input;
+          input.c[0] = byteToCol(col[i+4]);
+          GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+          sepCS->getCMYK(&input, &cmyk);
+          col[0] = colToByte(cmyk.c);
+          col[1] = colToByte(cmyk.m);
+          col[2] = colToByte(cmyk.y);
+          col[3] = colToByte(cmyk.k);
+          c += byteToDbl(col[0]);
+          m += byteToDbl(col[1]);
+          y += byteToDbl(col[2]);
+          k += byteToDbl(col[3]);
+        }
+      }
+      col[0] = dblToByte(clip01(c));
+      col[1] = dblToByte(clip01(m));
+      col[2] = dblToByte(clip01(y));
+      col[3] = dblToByte(clip01(k));
+    }
+    *line++ = col[0];
+    *line++ = col[1];
+    *line++ = col[2];
+    *line++ = col[3];
+  }
+}
+#endif
+
 SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) {
   if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8
 #if SPLASH_CMYK
-      && mode != splashModeCMYK8
+      && mode != splashModeCMYK8 && mode != splashModeDeviceN8
 #endif
      ) {
     error(errInternal, -1, "unsupported SplashBitmap mode");
@@ -414,6 +500,29 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int
         delete[] row;
       }
     break;
+    case splashModeDeviceN8:
+      if (writer->supportCMYK()) {
+        unsigned char *row = new unsigned char[4 * width];
+        for (int y = 0; y < height; y++) {
+          getCMYKLine(y, row);
+          if (!writer->writeRow(&row)) {
+            delete[] row;
+            return splashErrGeneric;
+          }
+        }
+        delete[] row;
+      } 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:
     {
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index 8bcc941..b413253 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -33,6 +33,7 @@
 #endif
 
 #include "SplashTypes.h"
+#include "poppler/GfxState.h"
 #include <stdio.h>
 
 class ImgWriter;
@@ -50,7 +51,7 @@ public:
   // upside-down, i.e., with the last row first in memory.
   SplashBitmap(int widthA, int heightA, int rowPad,
 	       SplashColorMode modeA, GBool alphaA,
-	       GBool topDown = gTrue);
+	       GBool topDown = gTrue, GooList *separationList = NULL);
 
   ~SplashBitmap();
 
@@ -62,6 +63,7 @@ public:
   SplashColorMode getMode() { return mode; }
   SplashColorPtr getDataPtr() { return data; }
   Guchar *getAlphaPtr() { return alpha; }
+  GooList *getSeparationList() { return separationList; }
 
   SplashError writePNMFile(char *fileName);
   SplashError writePNMFile(FILE *f);
@@ -73,6 +75,9 @@ public:
 
   void getPixel(int x, int y, SplashColorPtr pixel);
   void getRGBLine(int y, SplashColorPtr line);
+#if SPLASH_CMYK
+  void getCMYKLine(int y, SplashColorPtr line);
+#endif
   Guchar getAlpha(int x, int y);
 
   // Caller takes ownership of the bitmap data.  The SplashBitmap
@@ -90,6 +95,7 @@ private:
   SplashColorPtr data;		// pointer to row zero of the color data
   Guchar *alpha;		// pointer to row zero of the alpha data
 				//   (always top-down)
+  GooList *separationList; // list of spot colorants and their mapping functions
 
   friend class Splash;
 };
diff --git a/splash/SplashState.cc b/splash/SplashState.cc
index e258f66..fd2789d 100644
--- a/splash/SplashState.cc
+++ b/splash/SplashState.cc
@@ -40,7 +40,7 @@
 int splashColorModeNComps[] = {
   1, 1, 3, 3, 4
 #if SPLASH_CMYK
-  ,4
+  , 4, 4 + SPOT_NCOMPS
 #endif
 };
 
@@ -80,10 +80,14 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
     rgbTransferG[i] = (Guchar)i;
     rgbTransferB[i] = (Guchar)i;
     grayTransfer[i] = (Guchar)i;
+#if SPLASH_CMYK
     cmykTransferC[i] = (Guchar)i;
     cmykTransferM[i] = (Guchar)i;
     cmykTransferY[i] = (Guchar)i;
     cmykTransferK[i] = (Guchar)i;
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      deviceNTransfer[cp][i] = (Guchar)i;
+#endif
   }
   overprintMask = 0xffffffff;
   overprintAdditive = gFalse;
@@ -126,10 +130,14 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias,
     rgbTransferG[i] = (Guchar)i;
     rgbTransferB[i] = (Guchar)i;
     grayTransfer[i] = (Guchar)i;
+#if SPLASH_CMYK
     cmykTransferC[i] = (Guchar)i;
     cmykTransferM[i] = (Guchar)i;
     cmykTransferY[i] = (Guchar)i;
     cmykTransferK[i] = (Guchar)i;
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      deviceNTransfer[cp][i] = (Guchar)i;
+#endif
   }
   overprintMask = 0xffffffff;
   overprintAdditive = gFalse;
@@ -170,10 +178,14 @@ SplashState::SplashState(SplashState *state) {
   memcpy(rgbTransferG, state->rgbTransferG, 256);
   memcpy(rgbTransferB, state->rgbTransferB, 256);
   memcpy(grayTransfer, state->grayTransfer, 256);
+#if SPLASH_CMYK
   memcpy(cmykTransferC, state->cmykTransferC, 256);
   memcpy(cmykTransferM, state->cmykTransferM, 256);
   memcpy(cmykTransferY, state->cmykTransferY, 256);
   memcpy(cmykTransferK, state->cmykTransferK, 256);
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    memcpy(deviceNTransfer[cp], state->deviceNTransfer[cp], 256);
+#endif
   overprintMask = state->overprintMask;
   overprintAdditive = state->overprintAdditive;
   next = NULL;
@@ -228,16 +240,24 @@ void SplashState::setSoftMask(SplashBitmap *softMaskA) {
 
 void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
 			      Guchar *gray) {
+#if SPLASH_CMYK
   int i;
 
-  memcpy(rgbTransferR, red, 256);
-  memcpy(rgbTransferG, green, 256);
-  memcpy(rgbTransferB, blue, 256);
-  memcpy(grayTransfer, gray, 256);
   for (i = 0; i < 256; ++i) {
     cmykTransferC[i] = 255 - rgbTransferR[255 - i];
     cmykTransferM[i] = 255 - rgbTransferG[255 - i];
     cmykTransferY[i] = 255 - rgbTransferB[255 - i];
     cmykTransferK[i] = 255 - grayTransfer[255 - i];
   }
+  for (i = 0; i < 256; ++i) {
+    deviceNTransfer[0][i] = 255 - rgbTransferR[255 - i];
+    deviceNTransfer[1][i] = 255 - rgbTransferG[255 - i];
+    deviceNTransfer[2][i] = 255 - rgbTransferB[255 - i];
+    deviceNTransfer[3][i] = 255 - grayTransfer[255 - i];
+  }
+#endif
+  memcpy(rgbTransferR, red, 256);
+  memcpy(rgbTransferG, green, 256);
+  memcpy(rgbTransferB, blue, 256);
+  memcpy(grayTransfer, gray, 256);
 }
diff --git a/splash/SplashState.h b/splash/SplashState.h
index 01e7772..13d5478 100644
--- a/splash/SplashState.h
+++ b/splash/SplashState.h
@@ -121,10 +121,13 @@ private:
          rgbTransferG[256],
          rgbTransferB[256];
   Guchar grayTransfer[256];
+#if SPLASH_CMYK
   Guchar cmykTransferC[256],
          cmykTransferM[256],
          cmykTransferY[256],
          cmykTransferK[256];
+  Guchar deviceNTransfer[SPOT_NCOMPS+4][256];
+#endif
   Guint overprintMask;
   GBool overprintAdditive;
 
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h
index 65525b1..5a41e4f 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -46,6 +46,12 @@ typedef double SplashCoord;
 
 #define splashAASize 4
 
+#ifdef SPLASH_CMYK
+#ifndef SPOT_NCOMPS
+#define SPOT_NCOMPS 4
+#endif
+#endif
+
 //------------------------------------------------------------------------
 // colors
 //------------------------------------------------------------------------
@@ -62,8 +68,11 @@ enum SplashColorMode {
 				//   XBGRXBGR...
 #if SPLASH_CMYK
   ,
-  splashModeCMYK8		// 1 byte per component, 4 bytes per pixel:
+  splashModeCMYK8,	// 1 byte per component, 4 bytes per pixel:
 				//   CMYKCMYK...
+  splashModeDeviceN8		// 1 byte per component, 
+                        // 4 bytes + n bytes spot colors per pixel:
+				                // CMYKSSSSCMYKSSSS...
 #endif
 };
 
@@ -72,7 +81,11 @@ enum SplashColorMode {
 extern int splashColorModeNComps[];
 
 // max number of components in any SplashColor
+#if SPLASH_CMYK
+#define splashMaxColorComps SPOT_NCOMPS+4
+#else
 #define splashMaxColorComps 4
+#endif
 
 typedef Guchar SplashColor[splashMaxColorComps];
 typedef Guchar *SplashColorPtr;
@@ -93,6 +106,13 @@ static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; }
 static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; }
 static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; }
 static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; }
+
+// DEVICEN8
+static inline Guchar splashDeviceN8C(SplashColorPtr deviceN8) { return deviceN8[0]; }
+static inline Guchar splashDeviceN8M(SplashColorPtr deviceN8) { return deviceN8[1]; }
+static inline Guchar splashDeviceN8Y(SplashColorPtr deviceN8) { return deviceN8[2]; }
+static inline Guchar splashDeviceN8K(SplashColorPtr deviceN8) { return deviceN8[3]; }
+static inline Guchar splashDeviceN8S(SplashColorPtr deviceN8, int nSpot) { return deviceN8[4 + nSpot]; }
 #endif
 
 static inline void splashClearColor(SplashColorPtr dest) {
@@ -101,6 +121,8 @@ static inline void splashClearColor(SplashColorPtr dest) {
   dest[2] = 0;
 #if SPLASH_CMYK
   dest[3] = 0;
+  for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++)
+    dest[i] = 0;
 #endif
 }
 
@@ -110,6 +132,8 @@ static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) {
   dest[2] = src[2];
 #if SPLASH_CMYK
   dest[3] = src[3];
+  for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++)
+    dest[i] = src[i];
 #endif
 }
 
@@ -119,6 +143,8 @@ static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) {
   dest[2] ^= src[2];
 #if SPLASH_CMYK
   dest[3] ^= src[3];
+  for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++)
+    dest[i] ^= src[i];
 #endif
 }
 
diff --git a/utils/pdftoppm.cc b/utils/pdftoppm.cc
index 04a0dfb..f6086b7 100644
--- a/utils/pdftoppm.cc
+++ b/utils/pdftoppm.cc
@@ -353,10 +353,8 @@ int main(int argc, char *argv[]) {
 #if SPLASH_CMYK
   if (jpegcmyk || overprint) {
     globalParams->setOverprintPreview(gTrue);
-    paperColor[0] = 0;
-    paperColor[1] = 0;
-    paperColor[2] = 0;
-    paperColor[3] = 0;
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      paperColor[cp] = 0;
   } else 
 #endif
   {
@@ -367,7 +365,7 @@ int main(int argc, char *argv[]) {
   splashOut = new SplashOutputDev(mono ? splashModeMono1 :
 				    gray ? splashModeMono8 :
 #if SPLASH_CMYK
-				    (jpegcmyk || overprint) ? splashModeCMYK8 :
+				    (jpegcmyk || overprint) ? splashModeDeviceN8 :
 #endif
 				             splashModeRGB8, 4,
 				  gFalse, paperColor);


More information about the poppler mailing list