[poppler] 4 commits - poppler/GfxState.cc poppler/GfxState.h poppler/PSOutputDev.cc poppler/PSOutputDev.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu May 21 09:04:23 UTC 2020


 poppler/GfxState.cc    |  136 +++++++++++++++++++++++++++++++++++--------------
 poppler/GfxState.h     |   16 +++++
 poppler/PSOutputDev.cc |   77 ++++++++++++++++++++-------
 poppler/PSOutputDev.h  |    8 +-
 4 files changed, 174 insertions(+), 63 deletions(-)

New commits:
commit cc0f7960fd9dc4cfda8dc15cb061f891e909b386
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Sun May 17 21:00:26 2020 +0200

    only activate CSA support for the most recent lcms2 version
    
    Add a runtime check.

diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 339614b2..105ef1dc 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -224,6 +224,15 @@ unsigned int GfxColorTransform::unref() {
 
 char *GfxColorTransform::getPostScriptCSA()
 {
+#if LCMS_VERSION>=2070
+  // The runtime version check of lcms2 is only available from release 2.7 upwards.
+  // The generation of the CSA code only works reliably for version 2.10 and upwards.
+  // Cf. the explanation in the corresponding lcms2 merge request [1], and the original mail thread [2].
+  // [1] https://github.com/mm2/Little-CMS/pull/214
+  // [2] https://sourceforge.net/p/lcms/mailman/message/33182987/
+  if (cmsGetEncodedCMMversion() < 2100)
+    return nullptr;
+
   int size;
 
   if (psCSA)
@@ -245,6 +254,9 @@ char *GfxColorTransform::getPostScriptCSA()
   psCSA[size] = 0;
 
   return psCSA;
+#else
+  return nullptr;
+#endif
 }
 
 static cmsHPROFILE RGBProfile = nullptr;
commit 2334bea5208d0506e4eee02ed170abd7e73e2fe4
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Sun May 17 09:11:01 2020 +0200

    make the clang/clazy/Ubuntu/Android pipelines happy

diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index f5f11c13..339614b2 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -203,7 +203,7 @@ GfxColorTransform::GfxColorTransform(void *sourceProfileA, void *transformA, int
   cmsIntent = cmsIntentA;
   inputPixelType = inputPixelTypeA;
   transformPixelType = transformPixelTypeA;
-  psCSA = NULL;
+  psCSA = nullptr;
 }
 
 GfxColorTransform::~GfxColorTransform() {
@@ -229,15 +229,15 @@ char *GfxColorTransform::getPostScriptCSA()
   if (psCSA)
     return psCSA;
 
-  if (sourceProfile == NULL) {
-    error(errSyntaxWarning, -1, "profile is NULL");
-    return NULL;
+  if (sourceProfile == nullptr) {
+    error(errSyntaxWarning, -1, "profile is nullptr");
+    return nullptr;
   }
 
-  size = cmsGetPostScriptCSA(cmsGetProfileContextID(sourceProfile), sourceProfile, cmsIntent, 0, NULL, 0);
+  size = cmsGetPostScriptCSA(cmsGetProfileContextID(sourceProfile), sourceProfile, cmsIntent, 0, nullptr, 0);
   if (size == 0) {
-    error(errSyntaxWarning, -1, "PostScript CSA is NULL");
-    return NULL;
+    error(errSyntaxWarning, -1, "PostScript CSA is nullptr");
+    return nullptr;
   }
 
   psCSA = (char*)gmalloc(size+1);
@@ -1809,9 +1809,9 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
     error(errSyntaxError, -1, "Bad ICCBased color space");
     return nullptr;
   }
-#ifdef USE_CMS
   const Object &obj1Ref = arr->getNF(1);
   const Ref iccProfileStreamA = obj1Ref.isRef() ? obj1Ref.getRef() : Ref::INVALID();
+#ifdef USE_CMS
   // check cache
   if (out && iccProfileStreamA != Ref::INVALID()) {
     if (auto *item = out->getIccColorSpaceCache()->lookup(iccProfileStreamA)) {
@@ -1925,7 +1925,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
 	error(errSyntaxWarning, -1, "Can't create transform");
 	cs->lineTransform = nullptr;
       } else {
-	cs->lineTransform = new GfxColorTransform(NULL, transform, cmsIntent, cst, dcst);
+	cs->lineTransform = new GfxColorTransform(nullptr, transform, cmsIntent, cst, dcst);
       }
     }
     if (cs->transform == nullptr) {
@@ -2388,7 +2388,7 @@ char *GfxICCBasedColorSpace::getPostScriptCSA()
   if (transform)
     return transform->getPostScriptCSA();
   else
-    return NULL;
+    return nullptr;
 }
 #endif
 
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 3da66e8c..e07cd2a8 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -545,7 +545,7 @@ public:
 
   GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
 			const Ref *iccProfileStreamA);
-  ~GfxICCBasedColorSpace();
+  ~GfxICCBasedColorSpace() override;
   GfxColorSpace *copy() const override;
   GfxColorSpaceMode getMode() const override { return csICCBased; }
 
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 9a920fbb..f2df0d66 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -6808,7 +6808,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxState *state, GfxColorSpace *colorSpace,
     break;
 
   case csICCBased:
-#if USE_CMS
+#ifdef USE_CMS
     {
       GfxICCBasedColorSpace *iccBasedCS;
       iccBasedCS = (GfxICCBasedColorSpace *)colorSpace;
commit 1f698b44564b0313c019557616866eae11bf2cc9
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat May 16 22:08:32 2020 +0200

    Use ICC profiles in PS output
    
    When printing PDFs that use ICC based colors, Poppler always uses the alternate color space
    in the PostScript output (usually DeviceRGB or DeviceCMYK). The attached patch will use the
    ICC profile color space in the PS output. Most of the patch is modifying GfxColorTransform
    and callers to store the source profile as well as the transform. The GfxICCBasedColorSpace
    class has a new method, getPostScriptCSA(), which uses the LCMS function cmsGetPostScriptCSA()
    to generate the CIEBased color space dictionary equivalent to the ICC profile.
    
    Based on patch from issue #125.

diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 7141c9f8..f5f11c13 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -196,16 +196,22 @@ void GfxColorTransform::doTransform(void *in, void *out, unsigned int size) {
 }
 
 // transformA should be a cmsHTRANSFORM
-GfxColorTransform::GfxColorTransform(void *transformA, int cmsIntentA, unsigned int inputPixelTypeA, unsigned int transformPixelTypeA) {
+GfxColorTransform::GfxColorTransform(void *sourceProfileA, void *transformA, int cmsIntentA, unsigned int inputPixelTypeA, unsigned int transformPixelTypeA) {
+  sourceProfile = sourceProfileA;
   transform = transformA;
   refCount = 1;
   cmsIntent = cmsIntentA;
   inputPixelType = inputPixelTypeA;
   transformPixelType = transformPixelTypeA;
+  psCSA = NULL;
 }
 
 GfxColorTransform::~GfxColorTransform() {
+  if (sourceProfile)
+    cmsCloseProfile(sourceProfile);
   cmsDeleteTransform(transform);
+  if (psCSA)
+    gfree(psCSA);
 }
 
 void GfxColorTransform::ref() {
@@ -216,6 +222,31 @@ unsigned int GfxColorTransform::unref() {
   return --refCount;
 }
 
+char *GfxColorTransform::getPostScriptCSA()
+{
+  int size;
+
+  if (psCSA)
+    return psCSA;
+
+  if (sourceProfile == NULL) {
+    error(errSyntaxWarning, -1, "profile is NULL");
+    return NULL;
+  }
+
+  size = cmsGetPostScriptCSA(cmsGetProfileContextID(sourceProfile), sourceProfile, cmsIntent, 0, NULL, 0);
+  if (size == 0) {
+    error(errSyntaxWarning, -1, "PostScript CSA is NULL");
+    return NULL;
+  }
+
+  psCSA = (char*)gmalloc(size+1);
+  cmsGetPostScriptCSA(cmsGetProfileContextID(sourceProfile), sourceProfile, cmsIntent, 0, psCSA, size);
+  psCSA[size] = 0;
+
+  return psCSA;
+}
+
 static cmsHPROFILE RGBProfile = nullptr;
 static GooString *displayProfileName = nullptr; // display profile file Name
 static cmsHPROFILE displayProfile = nullptr; // display profile
@@ -248,9 +279,8 @@ void GfxColorSpace::setDisplayProfile(void *displayProfileA) {
 	  INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
     } else {
-      XYZ2DisplayTransform = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
+      XYZ2DisplayTransform = new GfxColorTransform(displayProfile, transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
     }
-    cmsCloseProfile(XYZProfile);
   }
 }
 
@@ -525,10 +555,10 @@ int GfxColorSpace::setupColorProfiles()
 	     CHANNELS_SH(nChannels) | BYTES_SH(1),
 	  INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
+      cmsCloseProfile(XYZProfile);
     } else {
-      XYZ2DisplayTransform = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
+      XYZ2DisplayTransform = new GfxColorTransform(XYZProfile, transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
     }
-    cmsCloseProfile(XYZProfile);
   }
   return 0;
 }
@@ -1789,16 +1819,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
       int transformIntent = cs->getIntent();
       int cmsIntent = INTENT_RELATIVE_COLORIMETRIC;
       if (state != nullptr) {
-        const char *intent = state->getRenderingIntent();
-        if (intent != nullptr) {
-          if (strcmp(intent, "AbsoluteColorimetric") == 0) {
-            cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC;
-          } else if (strcmp(intent, "Saturation") == 0) {
-            cmsIntent = INTENT_SATURATION;
-          } else if (strcmp(intent, "Perceptual") == 0) {
-            cmsIntent = INTENT_PERCEPTUAL;
-          }
-        }
+        cmsIntent = state->getCmsRenderingIntent();
       }
       if (transformIntent == cmsIntent) {
         return cs;
@@ -1883,16 +1904,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
 
     int cmsIntent = INTENT_RELATIVE_COLORIMETRIC;
     if (state != nullptr) {
-      const char *intent = state->getRenderingIntent();
-      if (intent != nullptr) {
-        if (strcmp(intent, "AbsoluteColorimetric") == 0) {
-          cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC;
-        } else if (strcmp(intent, "Saturation") == 0) {
-          cmsIntent = INTENT_SATURATION;
-        } else if (strcmp(intent, "Perceptual") == 0) {
-          cmsIntent = INTENT_PERCEPTUAL;
-        }
-      }
+      cmsIntent = state->getCmsRenderingIntent();
     }
     if ((transform = cmsCreateTransform(hp,
 	   COLORSPACE_SH(cst) |CHANNELS_SH(nCompsA) | BYTES_SH(1),
@@ -1903,7 +1915,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
       error(errSyntaxWarning, -1, "Can't create transform");
       cs->transform = nullptr;
     } else {
-      cs->transform = new GfxColorTransform(transform, cmsIntent, cst, dcst);
+      cs->transform = new GfxColorTransform(hp, transform, cmsIntent, cst, dcst);
     }
     if (dcst == PT_RGB || dcst == PT_CMYK) {
        // create line transform only when the display is RGB type color space 
@@ -1913,10 +1925,12 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
 	error(errSyntaxWarning, -1, "Can't create transform");
 	cs->lineTransform = nullptr;
       } else {
-	cs->lineTransform = new GfxColorTransform(transform, cmsIntent, cst, dcst);
+	cs->lineTransform = new GfxColorTransform(NULL, transform, cmsIntent, cst, dcst);
       }
     }
-    cmsCloseProfile(hp);
+    if (cs->transform == nullptr) {
+      cmsCloseProfile(hp);
+    }
   }
   // put this colorSpace into cache
   if (out && iccProfileStreamA != Ref::INVALID()) {
@@ -2368,6 +2382,16 @@ void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
 #endif
 }
 
+#ifdef USE_CMS
+char *GfxICCBasedColorSpace::getPostScriptCSA()
+{
+  if (transform)
+    return transform->getPostScriptCSA();
+  else
+    return NULL;
+}
+#endif
+
 //------------------------------------------------------------------------
 // GfxIndexedColorSpace
 //------------------------------------------------------------------------
@@ -6597,37 +6621,46 @@ void GfxState::setDisplayProfile(cmsHPROFILE localDisplayProfileA) {
 	     CHANNELS_SH(nChannels) | BYTES_SH(1),
 	  INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
+      cmsCloseProfile(XYZProfile);
     } else {
-      XYZ2DisplayTransformRelCol = new GfxColorTransform(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
+      XYZ2DisplayTransformRelCol = new GfxColorTransform(XYZProfile, transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
     }
+
+    XYZProfile = cmsCreateXYZProfile();
     if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
 	   localDisplayProfile,
 	   COLORSPACE_SH(localDisplayPixelType) |
 	     CHANNELS_SH(nChannels) | BYTES_SH(1),
 	  INTENT_ABSOLUTE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
+      cmsCloseProfile(XYZProfile);
     } else {
-      XYZ2DisplayTransformAbsCol = new GfxColorTransform(transform, INTENT_ABSOLUTE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
+      XYZ2DisplayTransformAbsCol = new GfxColorTransform(XYZProfile, transform, INTENT_ABSOLUTE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
     }
+
+    XYZProfile = cmsCreateXYZProfile();
     if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
 	   localDisplayProfile,
 	   COLORSPACE_SH(localDisplayPixelType) |
 	     CHANNELS_SH(nChannels) | BYTES_SH(1),
 	  INTENT_SATURATION,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
+      cmsCloseProfile(XYZProfile);
     } else {
-      XYZ2DisplayTransformSat = new GfxColorTransform(transform, INTENT_SATURATION, PT_XYZ, localDisplayPixelType);
+      XYZ2DisplayTransformSat = new GfxColorTransform(XYZProfile, transform, INTENT_SATURATION, PT_XYZ, localDisplayPixelType);
     }
+
+    XYZProfile = cmsCreateXYZProfile();
     if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
 	   localDisplayProfile,
 	   COLORSPACE_SH(localDisplayPixelType) |
 	     CHANNELS_SH(nChannels) | BYTES_SH(1),
 	  INTENT_PERCEPTUAL,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
+      cmsCloseProfile(XYZProfile);
     } else {
-      XYZ2DisplayTransformPerc = new GfxColorTransform(transform, INTENT_PERCEPTUAL, PT_XYZ, localDisplayPixelType);
+      XYZ2DisplayTransformPerc = new GfxColorTransform(XYZProfile, transform, INTENT_PERCEPTUAL, PT_XYZ, localDisplayPixelType);
     }
-    cmsCloseProfile(XYZProfile);
   }
 }
 
@@ -6648,6 +6681,21 @@ GfxColorTransform *GfxState::getXYZ2DisplayTransform() {
   return transform;
 }
 
+int GfxState::getCmsRenderingIntent() {
+  const char *intent = getRenderingIntent();
+  int cmsIntent = INTENT_RELATIVE_COLORIMETRIC;
+  if (intent) {
+    if (strcmp(intent, "AbsoluteColorimetric") == 0) {
+      cmsIntent = INTENT_ABSOLUTE_COLORIMETRIC;
+    } else if (strcmp(intent, "Saturation") == 0) {
+      cmsIntent = INTENT_SATURATION;
+    } else if (strcmp(intent, "Perceptual") == 0) {
+      cmsIntent = INTENT_PERCEPTUAL;
+    }
+  }
+  return cmsIntent;
+}
+
 #endif
 
 void GfxState::setPath(GfxPath *pathA) {
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 6d445ecf..3da66e8c 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -193,7 +193,8 @@ class GfxColorTransform {
 public:
   void doTransform(void *in, void *out, unsigned int size);
   // transformA should be a cmsHTRANSFORM
-  GfxColorTransform(void *transformA, int cmsIntent, unsigned int inputPixelType, unsigned int transformPixelType);
+  GfxColorTransform(void *sourceProfileA, void *transformA, int cmsIntent,
+                    unsigned int inputPixelType, unsigned int transformPixelType);
   ~GfxColorTransform();
   GfxColorTransform(const GfxColorTransform &) = delete;
   GfxColorTransform& operator=(const GfxColorTransform &) = delete;
@@ -202,13 +203,17 @@ public:
   int getTransformPixelType() const { return transformPixelType; }
   void ref();
   unsigned int unref();
+  void *getSourceProfile() { return sourceProfile; }
+  char *getPostScriptCSA();
 private:
   GfxColorTransform() {}
+  void *sourceProfile;
   void *transform;
   unsigned int refCount;
   int cmsIntent;
   unsigned int inputPixelType;
   unsigned int transformPixelType;
+  char *psCSA;
 };
 
 class GfxColorSpace {
@@ -569,6 +574,10 @@ public:
 
   // ICCBased-specific access.
   GfxColorSpace *getAlt() { return alt; }
+  Ref getRef() { return iccProfileStream; }
+#ifdef USE_CMS
+  char *getPostScriptCSA();
+#endif
 
 private:
 
@@ -1594,6 +1603,7 @@ public:
   void setDisplayProfile(void *localDisplayProfileA);
   void *getDisplayProfile() { return localDisplayProfile; }
   GfxColorTransform *getXYZ2DisplayTransform();
+  int getCmsRenderingIntent();
 #endif
 
   // Add to path.
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 8ad72c36..9a920fbb 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -3945,6 +3945,10 @@ void PSOutputDev::endPage() {
     (*overlayCbk)(this, overlayCbkData);
   }
 
+  for (const auto& item : iccEmitted) {
+      writePSFmt("userdict /{0:s} undef\n", item.c_str());
+  }
+  iccEmitted.clear();
 
   if (mode == psModeForm) {
     writePS("pdfEndPage\n");
@@ -3955,8 +3959,8 @@ void PSOutputDev::endPage() {
     if (!manualCtrl) {
       writePS("showpage\n");
     }
-      writePS("%%PageTrailer\n");
-      writePageTrailer();
+    writePS("%%PageTrailer\n");
+    writePageTrailer();
     }
 }
 
@@ -4022,7 +4026,7 @@ void PSOutputDev::updateFillColorSpace(GfxState *state) {
   case psLevel2:
   case psLevel3:
     if (state->getFillColorSpace()->getMode() != csPattern) {
-      dumpColorSpaceL2(state->getFillColorSpace(), true, false, false);
+      dumpColorSpaceL2(state, state->getFillColorSpace(), true, false, false);
       writePS(" cs\n");
     }
     break;
@@ -4043,7 +4047,7 @@ void PSOutputDev::updateStrokeColorSpace(GfxState *state) {
   case psLevel2:
   case psLevel3:
     if (state->getStrokeColorSpace()->getMode() != csPattern) {
-      dumpColorSpaceL2(state->getStrokeColorSpace(), true, false, false);
+      dumpColorSpaceL2(state, state->getStrokeColorSpace(), true, false, false);
       writePS(" CS\n");
     }
     break;
@@ -4940,7 +4944,7 @@ bool PSOutputDev::patchMeshShadedFill(GfxState *state,
   writePS("<<\n");
   writePS("  /ShadingType 7\n");
   writePS("  /ColorSpace ");
-  dumpColorSpaceL2(shading->getColorSpace(), false, false, false);
+  dumpColorSpaceL2(state, shading->getColorSpace(), false, false, false);
   writePS("\n");
   writePS("  /DataSource [\n");
 
@@ -5233,12 +5237,12 @@ void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
     break;
     case psLevel2:
     case psLevel2Sep:
-      doImageL2(ref, nullptr, invert, inlineImg, str, width, height, len,
+      doImageL2(state, ref, nullptr, invert, inlineImg, str, width, height, len,
                 nullptr, nullptr, 0, 0, false);
     break;
     case psLevel3:
     case psLevel3Sep:
-      doImageL3(ref, nullptr, invert, inlineImg, str, width, height, len,
+      doImageL3(state, ref, nullptr, invert, inlineImg, str, width, height, len,
                 nullptr, nullptr, 0, 0, false);
     break;
   }
@@ -5277,12 +5281,12 @@ void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
     break;
   case psLevel2:
   case psLevel2Sep:
-    doImageL2(ref, colorMap, false, inlineImg, str,
+    doImageL2(state, ref, colorMap, false, inlineImg, str,
 	      width, height, len, maskColors, nullptr, 0, 0, false);
     break;
   case psLevel3:
   case psLevel3Sep:
-    doImageL3(ref, colorMap, false, inlineImg, str,
+    doImageL3(state, ref, colorMap, false, inlineImg, str,
 	      width, height, len, maskColors, nullptr, 0, 0, false);
     break;
   }
@@ -5312,12 +5316,12 @@ void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
     break;
   case psLevel2:
   case psLevel2Sep:
-    doImageL2(ref, colorMap, false, false, str, width, height, len,
+    doImageL2(state, ref, colorMap, false, false, str, width, height, len,
 	      nullptr, maskStr, maskWidth, maskHeight, maskInvert);
     break;
   case psLevel3:
   case psLevel3Sep:
-    doImageL3(ref, colorMap, false, false, str, width, height, len,
+    doImageL3(state, ref, colorMap, false, false, str, width, height, len,
 	      nullptr, maskStr, maskWidth, maskHeight, maskInvert);
     break;
   }
@@ -5769,7 +5773,7 @@ void PSOutputDev::maskToClippingPath(Stream *maskStr, int maskWidth, int maskHei
   maskStr->close();
 }
 
-void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
+void PSOutputDev::doImageL2(GfxState* state, Object *ref, GfxImageColorMap *colorMap,
 			    bool invert, bool inlineImg,
 			    Stream *str, int width, int height, int len,
 			    const int *maskColors, Stream *maskStr,
@@ -5961,7 +5965,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
     bool isCustomColor =
       (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) &&
       colorMap->getColorSpace()->getMode() == csDeviceN;
-    dumpColorSpaceL2(colorMap->getColorSpace(), false, !isCustomColor, false);
+    dumpColorSpaceL2(state, colorMap->getColorSpace(), false, !isCustomColor, false);
     writePS(" setcolorspace\n");
   }
 
@@ -6249,7 +6253,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 }
 
 //~ this doesn't currently support OPI
-void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
+void PSOutputDev::doImageL3(GfxState *state, Object *ref, GfxImageColorMap *colorMap,
 			    bool invert, bool inlineImg,
 			    Stream *str, int width, int height, int len,
 			    const int *maskColors, Stream *maskStr,
@@ -6364,7 +6368,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     bool isCustomColor =
       (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) &&
       colorMap->getColorSpace()->getMode() == csDeviceN;
-    dumpColorSpaceL2(colorMap->getColorSpace(), false, !isCustomColor, false);
+    dumpColorSpaceL2(state, colorMap->getColorSpace(), false, !isCustomColor, false);
     writePS(" setcolorspace\n");
   }
 
@@ -6663,7 +6667,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   }
 }
 
-void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
+void PSOutputDev::dumpColorSpaceL2(GfxState *state, GfxColorSpace *colorSpace,
 				   bool genXform, bool updateColors,
 				   bool map01) {
   GfxCalGrayColorSpace *calGrayCS;
@@ -6804,17 +6808,48 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
     break;
 
   case csICCBased:
+#if USE_CMS
+    {
+      GfxICCBasedColorSpace *iccBasedCS;
+      iccBasedCS = (GfxICCBasedColorSpace *)colorSpace;
+      Ref ref = iccBasedCS->getRef();
+      int intent = state->getCmsRenderingIntent();
+      GooString *name = GooString::format("ICCBased-{0:d}-{1:d}-{2:d}", ref.num, ref.gen, intent);
+      const auto& it = iccEmitted.find(name->toStr());
+      if (it != iccEmitted.end()) {
+	writePSFmt("{0:t}", name);
+	if (genXform) {
+	  writePS(" {}");
+	}
+      } else {
+	char *csa = iccBasedCS->getPostScriptCSA();
+	if (csa) {
+	  writePSFmt("userdict /{0:t} {1:s} put\n", name, csa);
+	  iccEmitted.emplace(name->toStr());
+	  writePSFmt("{0:t}", name);
+	  if (genXform) {
+	    writePS(" {}");
+	  }
+	} else {
+	  dumpColorSpaceL2(state, ((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
+			   genXform, updateColors, false);
+	}
+      }
+      delete name;
+    }
+#else
     // there is no transform function to the alternate color space, so
     // we can use it directly
-    dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
+    dumpColorSpaceL2(state, ((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
 		     genXform, updateColors, false);
+#endif
     break;
 
   case csIndexed:
     indexedCS = (GfxIndexedColorSpace *)colorSpace;
     baseCS = indexedCS->getBase();
     writePS("[/Indexed ");
-    dumpColorSpaceL2(baseCS, false, false, true);
+    dumpColorSpaceL2(state, baseCS, false, false, true);
     n = indexedCS->getIndexHigh();
     numComps = baseCS->getNComps();
     lookup = indexedCS->getLookup();
@@ -6889,7 +6924,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
     writePS("[/Separation ");
     writePSString(separationCS->getName()->toStr());
     writePS(" ");
-    dumpColorSpaceL2(separationCS->getAlt(), false, false, false);
+    dumpColorSpaceL2(state, separationCS->getAlt(), false, false, false);
     writePS("\n");
     cvtFunction(separationCS->getFunc());
     writePS("]");
@@ -6911,7 +6946,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
         writePS(" ");
       }
       writePS("]\n");
-      dumpColorSpaceL2(deviceNCS->getAlt(), false, updateColors, false);
+      dumpColorSpaceL2(state, deviceNCS->getAlt(), false, updateColors, false);
       writePS("\n");
       cvtFunction(deviceNCS->getTintTransformFunc(), map01 && deviceNCS->getAlt()->getMode() == csLab);
       writePS("]\n");
@@ -6920,7 +6955,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
       }
     } else {
       // DeviceN color spaces are a Level 3 PostScript feature.
-      dumpColorSpaceL2(deviceNCS->getAlt(), false, updateColors, map01);
+      dumpColorSpaceL2(state, deviceNCS->getAlt(), false, updateColors, map01);
       if (genXform) {
         writePS(" ");
         cvtFunction(deviceNCS->getTintTransformFunc());
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index 5114a1d6..8641d14e 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -395,17 +395,17 @@ private:
 		    Stream *str, int width, int height, int len,
 		    const int *maskColors, Stream *maskStr,
 		    int maskWidth, int maskHeight, bool maskInvert);
-  void doImageL2(Object *ref, GfxImageColorMap *colorMap,
+  void doImageL2(GfxState *state, Object *ref, GfxImageColorMap *colorMap,
 		 bool invert, bool inlineImg,
 		 Stream *str, int width, int height, int len,
 		 const int *maskColors, Stream *maskStr,
 		 int maskWidth, int maskHeight, bool maskInvert);
-  void doImageL3(Object *ref, GfxImageColorMap *colorMap,
+  void doImageL3(GfxState *state, Object *ref, GfxImageColorMap *colorMap,
 		 bool invert, bool inlineImg,
 		 Stream *str, int width, int height, int len,
 		 const int *maskColors, Stream *maskStr,
 		 int maskWidth, int maskHeight, bool maskInvert);
-  void dumpColorSpaceL2(GfxColorSpace *colorSpace,
+  void dumpColorSpaceL2(GfxState *state, GfxColorSpace *colorSpace,
 			bool genXform, bool updateColors,
 			bool map01);
   bool tilingPatternFillL1(GfxState *state, Catalog *cat, Object *str,
@@ -557,6 +557,8 @@ private:
   bool enableLZW;		// enable LZW compression
   bool enableFlate;		// enable Flate compression
 
+  std::unordered_set<std::string> iccEmitted; // contains ICCBased CSAs that have been emitted
+
 #ifdef OPI_SUPPORT
   int opi13Nest;		// nesting level of OPI 1.3 objects
   int opi20Nest;		// nesting level of OPI 2.0 objects
commit d5efac76267c7adf7636514280614efcc1ac3392
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Sat May 16 14:06:56 2020 +0200

    Revert "GfxICCBasedColorSpace: Remove unused member variable"
    
    This reverts commit 8c8e0a143e975b16e6c437c03dc2267e7e8ff3fc.

diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 47ae1e5c..7141c9f8 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -1724,9 +1724,11 @@ void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
 // GfxICCBasedColorSpace
 //------------------------------------------------------------------------
 
-GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA) {
+GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+					     const Ref *iccProfileStreamA) {
   nComps = nCompsA;
   alt = altA;
+  iccProfileStream = *iccProfileStreamA;
   rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
   rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
 #ifdef USE_CMS
@@ -1751,7 +1753,7 @@ GfxColorSpace *GfxICCBasedColorSpace::copy() const {
   GfxICCBasedColorSpace *cs;
   int i;
 
-  cs = new GfxICCBasedColorSpace(nComps, alt->copy());
+  cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
   for (i = 0; i < 4; ++i) {
     cs->rangeMin[i] = rangeMin[i];
     cs->rangeMax[i] = rangeMax[i];
@@ -1846,7 +1848,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
       delete altA;
       return nullptr;
   }
-  cs = new GfxICCBasedColorSpace(nCompsA, altA);
+  cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
   obj2 = dict->lookup("Range");
   if (obj2.isArray() && obj2.arrayGetLength() == 2 * nCompsA) {
     for (i = 0; i < nCompsA; ++i) {
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 15c4c70f..6d445ecf 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -538,8 +538,9 @@ private:
 class GfxICCBasedColorSpace: public GfxColorSpace {
 public:
 
-  GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA);
-  ~GfxICCBasedColorSpace() override;
+  GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+			const Ref *iccProfileStreamA);
+  ~GfxICCBasedColorSpace();
   GfxColorSpace *copy() const override;
   GfxColorSpaceMode getMode() const override { return csICCBased; }
 
@@ -575,6 +576,7 @@ private:
   GfxColorSpace *alt;		// alternate color space
   double rangeMin[4];		// min values for each component
   double rangeMax[4];		// max values for each component
+  Ref iccProfileStream;		// the ICC profile
 #ifdef USE_CMS
   int getIntent() { return (transform != nullptr) ? transform->getIntent() : 0; }
   GfxColorTransform *transform;


More information about the poppler mailing list