[poppler] 4 commits - poppler/Gfx.cc poppler/GfxState.cc poppler/GfxState.h poppler/OutputDev.h poppler/Page.cc qt5/src utils/pdftocairo.cc

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jun 2 22:08:13 UTC 2020


 poppler/Gfx.cc              |    1 
 poppler/GfxState.cc         |  255 +++++++++++---------------------------------
 poppler/GfxState.h          |   18 +--
 poppler/OutputDev.h         |   26 ++--
 poppler/Page.cc             |   27 ++--
 qt5/src/CMakeLists.txt      |    3 
 qt5/src/poppler-document.cc |   23 ++-
 qt5/src/poppler-page.cc     |    8 +
 qt5/src/poppler-private.h   |    4 
 utils/pdftocairo.cc         |    4 
 10 files changed, 134 insertions(+), 235 deletions(-)

New commits:
commit 7257d33a3a938d5621aab0ed53b09c7ce797a646
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Fri May 22 18:23:09 2020 +0200

    add a dummy GfxState to Page::loadThumb for proper color space handling
    
    As far as I can tell this was the only remaining spot in the code where
    GfxColorSpace::parse was called without a properly initialized GfxState.

diff --git a/poppler/Page.cc b/poppler/Page.cc
index 670768ab..2ac178d7 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -643,7 +643,6 @@ bool Page::loadThumb(unsigned char **data_out,
   Object obj1;
   Dict *dict;
   GfxColorSpace *colorSpace;
-  bool success = false;
   Stream *str;
   GfxImageColorMap *colorMap;
 
@@ -658,17 +657,17 @@ bool Page::loadThumb(unsigned char **data_out,
   str = fetched_thumb.getStream(); 
 		
   if (!dict->lookupInt("Width", "W", &width))
-    goto fail1;
+    return false;
   if (!dict->lookupInt("Height", "H", &height))
-    goto fail1;
+    return false;
   if (!dict->lookupInt("BitsPerComponent", "BPC", &bits))
-    goto fail1;
+    return false;
 		
   /* Check for invalid dimensions and integer overflow. */
   if (width <= 0 || height <= 0)
-    goto fail1;
+    return false;
   if (width > INT_MAX / 3 / height)
-    goto fail1;
+    return false;
   pixbufdatasize = width * height * 3;
 
   /* Get color space */
@@ -676,10 +675,14 @@ bool Page::loadThumb(unsigned char **data_out,
   if (obj1.isNull ()) {
     obj1 = dict->lookup ("CS");
   }
-  colorSpace = GfxColorSpace::parse(nullptr, &obj1, nullptr, nullptr);
+  // Just initialize some dummy GfxState for GfxColorSpace::parse.
+  // This will set a sRGB profile for ICC-based colorspaces.
+  auto pdfrectangle = std::make_shared<PDFRectangle>();
+  auto state = std::make_shared<GfxState>(72.0,72.0,pdfrectangle.get(), 0, false);
+  colorSpace = GfxColorSpace::parse(nullptr, &obj1, nullptr, state.get());
   if (!colorSpace) {
     fprintf (stderr, "Error: Cannot parse color space\n");
-    goto fail1;
+    return false;
   }
 
   obj1 = dict->lookup("Decode");
@@ -690,7 +693,7 @@ bool Page::loadThumb(unsigned char **data_out,
   if (!colorMap->isOk()) {
     fprintf (stderr, "Error: invalid colormap\n");
     delete colorMap;
-    goto fail1;
+    return false;
   }
 
   if (data_out) {
@@ -718,8 +721,6 @@ bool Page::loadThumb(unsigned char **data_out,
     delete imgstr;
   }
 
-  success = true;
-
   if (width_out)
     *width_out = width;
   if (height_out)
@@ -728,8 +729,8 @@ bool Page::loadThumb(unsigned char **data_out,
     *rowstride_out = width * 3;
 
   delete colorMap;
- fail1:
-  return success;
+
+  return true;
 }
 
 void Page::makeBox(double hDPI, double vDPI, int rotate,
commit b2141b8921525141560b8e4ef5a351f505d7cf5b
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Fri May 22 18:17:16 2020 +0200

    cleanup displayprofile initialization
    
    There were a bunch of global variables that were used to initilize the first version
    of the display profiles. This code was removed, and all the static initilization was moved
    from GfxColorSpace to GfxState. Furthermore, for most "users" the setting of the
    display profile was moved from the static GfxColorSpace::setDisplayProfile function
    to the OutputDev class. The latter is now invoked early in the initilization of Gfx
    to set the initial state in the GfxState instance.

diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 2a5b295c..37a8996a 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -548,6 +548,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
   // initialize
   out = outA;
   state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown());
+  out->initGfxState(state);
   stackHeight = 1;
   pushStateGuard();
   fontChanged = false;
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 51922565..e8091681 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -189,9 +189,6 @@ static const std::map<unsigned int, unsigned int>::size_type CMSCACHE_LIMIT = 20
 #include <lcms2.h>
 #define LCMS_FLAGS cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION
 
-#define COLOR_PROFILE_DIR "/ColorProfiles/"
-#define GLOBAL_COLOR_PROFILE_DIR POPPLER_DATADIR COLOR_PROFILE_DIR
-
 static void lcmsprofiledeleter(void* profile)
 {
     cmsCloseProfile(profile);
@@ -221,59 +218,9 @@ GfxColorTransform::~GfxColorTransform() {
   cmsDeleteTransform(transform);
 }
 
-static GfxLCMSProfilePtr RGBProfile = nullptr;
-static GooString *displayProfileName = nullptr; // display profile file Name
-static GfxLCMSProfilePtr displayProfile = nullptr; // display profile
-static unsigned int displayPixelType = 0;
-static std::shared_ptr<GfxColorTransform> XYZ2DisplayTransform = nullptr;
-
 // convert color space signature to cmsColor type 
 static unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs);
 static unsigned int getCMSNChannels(cmsColorSpaceSignature cs);
-static GfxLCMSProfilePtr loadColorProfile(const char *fileName);
-
-void GfxColorSpace::setDisplayProfile(const GfxLCMSProfilePtr& displayProfileA) {
-  if (displayProfile) {
-    error(errInternal, -1, "The display color profile can only be set once before any rendering is done.");
-    return;
-  }
-  displayProfile = displayProfileA;
-  if (displayProfile) {
-    cmsHTRANSFORM transform;
-    unsigned int nChannels;
-
-    displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile.get()));
-    nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile.get()));
-    // create transform from XYZ
-    auto XYZProfile = make_GfxLCMSProfilePtr(cmsCreateXYZProfile());
-    if ((transform = cmsCreateTransform(XYZProfile.get(), TYPE_XYZ_DBL,
-	   displayProfile.get(),
-	   COLORSPACE_SH(displayPixelType) |
-	     CHANNELS_SH(nChannels) | BYTES_SH(1),
-	  INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
-      error(errSyntaxWarning, -1, "Can't create Lab transform");
-    } else {
-      XYZ2DisplayTransform = std::make_shared<GfxColorTransform>(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
-    }
-  }
-}
-
-void GfxColorSpace::setDisplayProfileName(GooString *name) {
-  if (displayProfile != nullptr) {
-    error(errInternal, -1, "The display color profile can only be set before any rendering is done.");
-    return;
-  }
-  delete displayProfileName;
-  displayProfileName = name->copy();
-}
-
-GfxLCMSProfilePtr GfxColorSpace::getRGBProfile() {
-  return RGBProfile;
-}
-
-GfxLCMSProfilePtr GfxColorSpace::getDisplayProfile() {
-  return displayProfile;
-}
 
 #endif
 
@@ -459,83 +406,12 @@ const char *GfxColorSpace::getColorSpaceModeName(int idx) {
 }
 
 #ifdef USE_CMS
-GfxLCMSProfilePtr loadColorProfile(const char *fileName)
-{
-  cmsHPROFILE hp = nullptr;
-  FILE *fp;
-
-  if (fileName[0] == '/') {
-    // full path
-    // check if open the file
-    if ((fp = openFile(fileName,"r")) != nullptr) {
-      fclose(fp);
-      hp = cmsOpenProfileFromFile(fileName,"r");
-    }
-    return make_GfxLCMSProfilePtr(hp);
-  }
-  // try to load from global directory
-  GooString *path = new GooString(GLOBAL_COLOR_PROFILE_DIR);
-  path->append(fileName);
-  // check if open the file
-  if ((fp = openFile(path->c_str(),"r")) != nullptr) {
-    fclose(fp);
-    hp = cmsOpenProfileFromFile(path->c_str(),"r");
-  }
-  delete path;
-  return make_GfxLCMSProfilePtr(hp);
-}
 
 static void CMSError(cmsContext /*contextId*/, cmsUInt32Number /*ecode*/, const char *text)
 {
     error(errSyntaxWarning, -1, "{0:s}", text);
 }
 
-int GfxColorSpace::setupColorProfiles()
-{
-  static bool initialized = false;
-  cmsHTRANSFORM transform;
-  unsigned int nChannels;
-
-  // do only once
-  if (initialized) return 0;
-  initialized = true;
-
-  // set error handlor
-  cmsSetLogErrorHandler(CMSError);
-
-  if (!displayProfile) {
-    // load display profile if it was not already loaded.
-    if (displayProfileName == nullptr) {
-      displayProfile = loadColorProfile("display.icc");
-    } else if (displayProfileName->getLength() > 0) {
-      displayProfile = loadColorProfile(displayProfileName->c_str());
-    }
-  }
-  // load RGB profile
-  RGBProfile = loadColorProfile("RGB.icc");
-  if (!RGBProfile) {
-    /* use built in sRGB profile */
-    RGBProfile = make_GfxLCMSProfilePtr(cmsCreate_sRGBProfile());
-  }
-  // create transforms
-  if (displayProfile) {
-    displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile.get()));
-    nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile.get()));
-    // create transform from XYZ
-    auto XYZProfile = make_GfxLCMSProfilePtr(cmsCreateXYZProfile());
-    if ((transform = cmsCreateTransform(XYZProfile.get(), TYPE_XYZ_DBL,
-	   displayProfile.get(),
-	   COLORSPACE_SH(displayPixelType) |
-	     CHANNELS_SH(nChannels) | BYTES_SH(1),
-	  INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
-      error(errSyntaxWarning, -1, "Can't create Lab transform");
-    } else {
-      XYZ2DisplayTransform = std::make_shared<GfxColorTransform>(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
-    }
-  }
-  return 0;
-}
-
 unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs)
 {
     switch (cs) {
@@ -815,7 +691,7 @@ GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, GfxState *state) {
 		xyzrgb[2][1] * cs->whiteY +
 		xyzrgb[2][2] * cs->whiteZ);
 #ifdef USE_CMS
-  cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform;
+  cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : nullptr;
 #endif
   return cs;
 }
@@ -1175,7 +1051,7 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, GfxState *state) {
 		xyzrgb[2][2] * cs->whiteZ);
 
 #ifdef USE_CMS
-  cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform;
+  cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : nullptr;
 #endif
   return cs;
 }
@@ -1521,7 +1397,7 @@ GfxColorSpace *GfxLabColorSpace::parse(Array *arr, GfxState *state) {
 		xyzrgb[2][2] * cs->whiteZ);
 
 #ifdef USE_CMS
-  cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : XYZ2DisplayTransform;
+  cs->transform = (state != nullptr) ? state->getXYZ2DisplayTransform() : nullptr;
 #endif
   return cs;
 }
@@ -1838,12 +1714,9 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
   if (!hp) {
     error(errSyntaxWarning, -1, "read ICCBased color space profile error");
   } else {
-    auto dhp = (state != nullptr && state->getDisplayProfile() != nullptr) ? state->getDisplayProfile() : displayProfile;
+    auto dhp = (state != nullptr && state->getDisplayProfile() != nullptr) ? state->getDisplayProfile() : nullptr;
     if (!dhp) {
-      if (unlikely(!RGBProfile)) {
-        GfxColorSpace::setupColorProfiles();
-      }
-      dhp = RGBProfile;
+      dhp = GfxState::sRGBProfile;
     }
     unsigned int cst = getCMSColorSpaceType(cmsGetColorSpace(hp.get()));
     unsigned int dNChannels = getCMSNChannels(cmsGetColorSpace(dhp.get()));
@@ -6461,12 +6334,22 @@ GfxState::GfxState(double hDPIA, double vDPIA, const PDFRectangle *pageBox,
 
   saved = nullptr;
 #ifdef USE_CMS
-  GfxColorSpace::setupColorProfiles();
   XYZ2DisplayTransformRelCol = nullptr;
   XYZ2DisplayTransformAbsCol = nullptr;
   XYZ2DisplayTransformSat = nullptr;
   XYZ2DisplayTransformPerc = nullptr;
   localDisplayProfile = nullptr;
+
+  if (!sRGBProfile) {
+    // This is probably the one of the first invocations of lcms2, so we set the error handler
+    cmsSetLogErrorHandler(CMSError);
+
+    sRGBProfile = make_GfxLCMSProfilePtr(cmsCreate_sRGBProfile());
+  }
+
+  if (!XYZProfile) {
+    XYZProfile = make_GfxLCMSProfilePtr(cmsCreateXYZProfile());
+  }
 #endif
 }
 
@@ -6600,6 +6483,10 @@ GfxState::GfxState(const GfxState *state, bool copyPath) {
 }
 
 #ifdef USE_CMS
+
+GfxLCMSProfilePtr GfxState::sRGBProfile = nullptr;
+GfxLCMSProfilePtr GfxState::XYZProfile = nullptr;
+
 void GfxState::setDisplayProfile(const GfxLCMSProfilePtr& localDisplayProfileA) {
   localDisplayProfile = localDisplayProfileA;
   if (localDisplayProfile) {
@@ -6610,7 +6497,6 @@ void GfxState::setDisplayProfile(const GfxLCMSProfilePtr& localDisplayProfileA)
     localDisplayPixelType = getCMSColorSpaceType(cmsGetColorSpace(localDisplayProfile.get()));
     nChannels = getCMSNChannels(cmsGetColorSpace(localDisplayProfile.get()));
     // create transform from XYZ
-    auto XYZProfile = make_GfxLCMSProfilePtr(cmsCreateXYZProfile());
     if ((transform = cmsCreateTransform(XYZProfile.get(), TYPE_XYZ_DBL,
 	   localDisplayProfile.get(),
 	   COLORSPACE_SH(localDisplayPixelType) |
@@ -6662,9 +6548,6 @@ std::shared_ptr<GfxColorTransform> GfxState::getXYZ2DisplayTransform() {
   } else if (strcmp(renderingIntent, "Perceptual") == 0) {
     transform = XYZ2DisplayTransformPerc;
   }
-  if (!transform) {
-    transform = XYZ2DisplayTransform;
-  }
   return transform;
 }
 
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index be5bb7df..c30c1a99 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -283,13 +283,6 @@ public:
   // Return the name of the <idx>th color space mode.
   static const char *getColorSpaceModeName(int idx);
 
-#ifdef USE_CMS
-  static int setupColorProfiles();
-  static void setDisplayProfile(const GfxLCMSProfilePtr& displayProfileA);
-  static void setDisplayProfileName(GooString *name);
-  static GfxLCMSProfilePtr getRGBProfile();
-  static GfxLCMSProfilePtr getDisplayProfile();
-#endif
 protected:
 
   unsigned int overprintMask;
@@ -1608,6 +1601,7 @@ public:
   GfxLCMSProfilePtr getDisplayProfile() { return localDisplayProfile; }
   std::shared_ptr<GfxColorTransform> getXYZ2DisplayTransform();
   int getCmsRenderingIntent();
+  static GfxLCMSProfilePtr sRGBProfile;
 #endif
 
   // Add to path.
@@ -1709,6 +1703,7 @@ private:
   std::shared_ptr<GfxColorTransform> XYZ2DisplayTransformAbsCol;
   std::shared_ptr<GfxColorTransform> XYZ2DisplayTransformSat;
   std::shared_ptr<GfxColorTransform> XYZ2DisplayTransformPerc;
+  static GfxLCMSProfilePtr XYZProfile;
 #endif
 };
 
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index 9dc052ae..609fa8d5 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -40,6 +40,7 @@
 #include "Object.h"
 #include "PopplerCache.h"
 #include "ProfileData.h"
+#include "GfxState.h"
 #include <memory>
 #include <unordered_map>
 #include <string>
@@ -47,21 +48,7 @@
 class Annot;
 class Dict;
 class GooString;
-class GfxState;
 class Gfx;
-struct GfxColor;
-class GfxColorSpace;
-#ifdef USE_CMS
-class GfxICCBasedColorSpace;
-#endif
-class GfxImageColorMap;
-class GfxFunctionShading;
-class GfxAxialShading;
-class GfxGouraudTriangleShading;
-class GfxPatchMeshShading;
-class GfxRadialShading;
-class GfxGouraudTriangleShading;
-class GfxPatchMeshShading;
 class Stream;
 class Links;
 class AnnotLink;
@@ -150,6 +137,13 @@ public:
   // Dump page contents to display.
   virtual void dump() {}
 
+  virtual void initGfxState (GfxState* state)
+  {
+#ifdef USE_CMS
+    state->setDisplayProfile(displayprofile);
+#endif
+  }
+
   //----- coordinate conversion
 
   // Convert between device and user coordinates.
@@ -370,6 +364,8 @@ public:
 #endif
 
 #ifdef USE_CMS
+  void setDisplayProfile(const GfxLCMSProfilePtr& profile) { displayprofile = profile; }
+
   PopplerCache<Ref, GfxICCBasedColorSpace> *getIccColorSpaceCache() { return &iccColorSpaceCache; }
 #endif
 
@@ -380,6 +376,8 @@ private:
   std::unique_ptr<std::unordered_map<std::string, ProfileData>> profileHash;
 
 #ifdef USE_CMS
+  GfxLCMSProfilePtr displayprofile;
+
   PopplerCache<Ref, GfxICCBasedColorSpace> iccColorSpaceCache;
 #endif
 };
diff --git a/qt5/src/CMakeLists.txt b/qt5/src/CMakeLists.txt
index e75b5730..bbcd612d 100644
--- a/qt5/src/CMakeLists.txt
+++ b/qt5/src/CMakeLists.txt
@@ -52,6 +52,9 @@ endif()
 if (ENABLE_NSS3)
     target_include_directories(poppler-qt5 SYSTEM PRIVATE ${NSS3_INCLUDE_DIRS})
 endif()
+if(USE_CMS)
+    target_link_libraries(poppler-qt5 poppler ${LCMS2_LIBRARIES})
+endif()
 install(TARGETS poppler-qt5 RUNTIME DESTINATION bin LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
 
 install(FILES
diff --git a/qt5/src/poppler-document.cc b/qt5/src/poppler-document.cc
index a40d4bac..cc6f01ad 100644
--- a/qt5/src/poppler-document.cc
+++ b/qt5/src/poppler-document.cc
@@ -649,7 +649,16 @@ namespace Poppler {
     void Document::setColorDisplayProfile(void* outputProfileA)
     {
 #if defined(USE_CMS)
-        GfxColorSpace::setDisplayProfile(make_GfxLCMSProfilePtr(outputProfileA));
+        if (m_doc->m_sRGBProfile && m_doc->m_sRGBProfile.get() == outputProfileA) {
+            // Catch the special case that the user passes the sRGB profile
+            m_doc->m_displayProfile = m_doc->m_sRGBProfile;
+            return;
+        }
+        if (m_doc->m_displayProfile && m_doc->m_displayProfile.get() == outputProfileA) {
+            // Catch the special case that the user passes the display profile
+            return;
+        }
+        m_doc->m_displayProfile = make_GfxLCMSProfilePtr(outputProfileA);
 #else
         Q_UNUSED(outputProfileA);
 #endif
@@ -658,9 +667,8 @@ namespace Poppler {
     void Document::setColorDisplayProfileName(const QString &name)
     {
 #if defined(USE_CMS)
-        GooString *profileName = QStringToGooString( name );
-        GfxColorSpace::setDisplayProfileName(profileName);
-        delete profileName;
+        void* rawprofile = cmsOpenProfileFromFile(name.toLocal8Bit().constData(),"r");
+        m_doc->m_displayProfile = make_GfxLCMSProfilePtr(rawprofile);
 #else
         Q_UNUSED(name);
 #endif
@@ -669,7 +677,10 @@ namespace Poppler {
     void* Document::colorRgbProfile() const
     {
 #if defined(USE_CMS)
-        return GfxColorSpace::getRGBProfile().get();
+        if (!m_doc->m_sRGBProfile) {
+            m_doc->m_sRGBProfile = make_GfxLCMSProfilePtr(cmsCreate_sRGBProfile());
+        }
+        return m_doc->m_sRGBProfile.get();
 #else
         return nullptr;
 #endif
@@ -678,7 +689,7 @@ namespace Poppler {
     void* Document::colorDisplayProfile() const
     {
 #if defined(USE_CMS)
-       return GfxColorSpace::getDisplayProfile().get();
+       return m_doc->m_displayProfile.get();
 #else
        return nullptr;
 #endif
diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
index dab4bc43..e06e88bf 100644
--- a/qt5/src/poppler-page.cc
+++ b/qt5/src/poppler-page.cc
@@ -592,6 +592,10 @@ QImage Page::renderToImage(double xres, double yres, int xPos, int yPos, int w,
       splash_output.setFreeTypeHinting(m_page->parentDoc->m_hints & Document::TextHinting ? true : false,
                                         m_page->parentDoc->m_hints & Document::TextSlightHinting ? true : false);
 
+#ifdef USE_CMS
+      splash_output.setDisplayProfile(m_page->parentDoc->m_displayProfile);
+#endif
+
       splash_output.startDoc(m_page->parentDoc->doc);
 
       const bool hideAnnotations = m_page->parentDoc->m_hints & Document::HideAnnotations;
@@ -624,6 +628,10 @@ QImage Page::renderToImage(double xres, double yres, int xPos, int yPos, int w,
 
       arthur_output.setHintingPreference(QFontHintingFromPopplerHinting(m_page->parentDoc->m_hints));
 
+#ifdef USE_CMS
+      arthur_output.setDisplayProfile(m_page->parentDoc->m_displayProfile);
+#endif
+
       arthur_output.setCallbacks(partialUpdateCallback, shouldDoPartialUpdateCallback, shouldAbortRenderCallback, payload);
       renderToArthur(&arthur_output, &painter, m_page, xres, yres, xPos, yPos, w, h, rotate, DontSaveAndRestore);
       painter.end();
diff --git a/qt5/src/poppler-private.h b/qt5/src/poppler-private.h
index 1ccea2b9..899b4850 100644
--- a/qt5/src/poppler-private.h
+++ b/qt5/src/poppler-private.h
@@ -178,6 +178,10 @@ namespace Poppler {
 	QPointer<OptContentModel> m_optContentModel;
 	QColor paperColor;
 	int m_hints;
+#ifdef USE_CMS
+        GfxLCMSProfilePtr m_sRGBProfile;
+        GfxLCMSProfilePtr m_displayProfile;
+#endif
     };
 
     class FontInfoData
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index 4f51d427..a6d9384f 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -1137,7 +1137,6 @@ int main(int argc, char *argv[]) {
   } else {
     profile = make_GfxLCMSProfilePtr(cmsCreate_sRGBProfile());
   }
-  GfxColorSpace::setDisplayProfile(profile);
 #endif
 
   doc = PDFDocFactory().createPDFDoc(*fileName, ownerPW, userPW);
@@ -1212,6 +1211,9 @@ int main(int argc, char *argv[]) {
 
 
   cairoOut = new CairoOutputDev();
+#ifdef USE_CMS
+  cairoOut->setDisplayProfile(profile);
+#endif
   cairoOut->startDoc(doc);
   if (sz != 0)
     crop_w = crop_h = sz;
commit 7dc4f0b56057aa4facc7ba559998d6dac5042792
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Fri May 22 11:47:54 2020 +0200

    remove sourceProfile variable from GfxColorTransform
    
    The sourceProfile variable was initially introduced in commit 1f698b44564b0313c019557616866eae11bf2cc9
    for the Postscript CSA generation code. With the last commit this code has been moved to GfxICCBasedColorSpace
    anyway, so there is no use anymore for storing the profile in GfxColorTransform.

diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 2fb78c1c..51922565 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -210,8 +210,7 @@ void GfxColorTransform::doTransform(void *in, void *out, unsigned int size) {
 }
 
 // transformA should be a cmsHTRANSFORM
-GfxColorTransform::GfxColorTransform(const GfxLCMSProfilePtr& sourceProfileA, void *transformA, int cmsIntentA, unsigned int inputPixelTypeA, unsigned int transformPixelTypeA) {
-  sourceProfile = sourceProfileA;
+GfxColorTransform::GfxColorTransform(void *transformA, int cmsIntentA, unsigned int inputPixelTypeA, unsigned int transformPixelTypeA) {
   transform = transformA;
   cmsIntent = cmsIntentA;
   inputPixelType = inputPixelTypeA;
@@ -254,7 +253,7 @@ void GfxColorSpace::setDisplayProfile(const GfxLCMSProfilePtr& displayProfileA)
 	  INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
     } else {
-      XYZ2DisplayTransform = std::make_shared<GfxColorTransform>(displayProfile, transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
+      XYZ2DisplayTransform = std::make_shared<GfxColorTransform>(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
     }
   }
 }
@@ -531,7 +530,7 @@ int GfxColorSpace::setupColorProfiles()
 	  INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
     } else {
-      XYZ2DisplayTransform = std::make_shared<GfxColorTransform>(XYZProfile, transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
+      XYZ2DisplayTransform = std::make_shared<GfxColorTransform>(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, displayPixelType);
     }
   }
   return 0;
@@ -1864,7 +1863,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
       error(errSyntaxWarning, -1, "Can't create transform");
       cs->transform = nullptr;
     } else {
-      cs->transform = std::make_shared<GfxColorTransform>(hp, transform, cmsIntent, cst, dcst);
+      cs->transform = std::make_shared<GfxColorTransform>(transform, cmsIntent, cst, dcst);
     }
     if (dcst == PT_RGB || dcst == PT_CMYK) {
        // create line transform only when the display is RGB type color space 
@@ -1874,7 +1873,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
 	error(errSyntaxWarning, -1, "Can't create transform");
 	cs->lineTransform = nullptr;
       } else {
-	cs->lineTransform = std::make_shared<GfxColorTransform>(hp, transform, cmsIntent, cst, dcst);
+	cs->lineTransform = std::make_shared<GfxColorTransform>(transform, cmsIntent, cst, dcst);
       }
     }
   }
@@ -6619,7 +6618,7 @@ void GfxState::setDisplayProfile(const GfxLCMSProfilePtr& localDisplayProfileA)
 	  INTENT_RELATIVE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
     } else {
-      XYZ2DisplayTransformRelCol = std::make_shared<GfxColorTransform>(XYZProfile, transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
+      XYZ2DisplayTransformRelCol = std::make_shared<GfxColorTransform>(transform, INTENT_RELATIVE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
     }
 
     if ((transform = cmsCreateTransform(XYZProfile.get(), TYPE_XYZ_DBL,
@@ -6629,7 +6628,7 @@ void GfxState::setDisplayProfile(const GfxLCMSProfilePtr& localDisplayProfileA)
 	  INTENT_ABSOLUTE_COLORIMETRIC,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
     } else {
-      XYZ2DisplayTransformAbsCol = std::make_shared<GfxColorTransform>(XYZProfile, transform, INTENT_ABSOLUTE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
+      XYZ2DisplayTransformAbsCol = std::make_shared<GfxColorTransform>(transform, INTENT_ABSOLUTE_COLORIMETRIC, PT_XYZ, localDisplayPixelType);
     }
 
     if ((transform = cmsCreateTransform(XYZProfile.get(), TYPE_XYZ_DBL,
@@ -6639,7 +6638,7 @@ void GfxState::setDisplayProfile(const GfxLCMSProfilePtr& localDisplayProfileA)
 	  INTENT_SATURATION,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
     } else {
-      XYZ2DisplayTransformSat = std::make_shared<GfxColorTransform>(XYZProfile, transform, INTENT_SATURATION, PT_XYZ, localDisplayPixelType);
+      XYZ2DisplayTransformSat = std::make_shared<GfxColorTransform>(transform, INTENT_SATURATION, PT_XYZ, localDisplayPixelType);
     }
 
     if ((transform = cmsCreateTransform(XYZProfile.get(), TYPE_XYZ_DBL,
@@ -6649,7 +6648,7 @@ void GfxState::setDisplayProfile(const GfxLCMSProfilePtr& localDisplayProfileA)
 	  INTENT_PERCEPTUAL,LCMS_FLAGS)) == nullptr) {
       error(errSyntaxWarning, -1, "Can't create Lab transform");
     } else {
-      XYZ2DisplayTransformPerc = std::make_shared<GfxColorTransform>(XYZProfile, transform, INTENT_PERCEPTUAL, PT_XYZ, localDisplayPixelType);
+      XYZ2DisplayTransformPerc = std::make_shared<GfxColorTransform>(transform, INTENT_PERCEPTUAL, PT_XYZ, localDisplayPixelType);
     }
   }
 }
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index f79c6bc7..be5bb7df 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -204,7 +204,7 @@ class GfxColorTransform {
 public:
   void doTransform(void *in, void *out, unsigned int size);
   // transformA should be a cmsHTRANSFORM
-  GfxColorTransform(const GfxLCMSProfilePtr& sourceProfileA, void *transformA, int cmsIntent,
+  GfxColorTransform(void *transformA, int cmsIntent,
                     unsigned int inputPixelType, unsigned int transformPixelType);
   ~GfxColorTransform();
   GfxColorTransform(const GfxColorTransform &) = delete;
@@ -212,10 +212,8 @@ public:
   int getIntent() const { return cmsIntent; }
   int getInputPixelType() const { return inputPixelType; }
   int getTransformPixelType() const { return transformPixelType; }
-  GfxLCMSProfilePtr getSourceProfile() { return sourceProfile; }
 private:
   GfxColorTransform() {}
-  GfxLCMSProfilePtr sourceProfile;
   void *transform;
   int cmsIntent;
   unsigned int inputPixelType;
commit 344f3e655cb0018421350c1a9916381d686025b6
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Fri May 22 11:39:28 2020 +0200

    move Postscript CSA generation from GfxColorTransform to GfxICCBasedColorSpace
    
    With proper ref counting for profiles in place, we can now let GfxICCBasedColorSpace
    directly generate the CSA rather than going through GfxColorTransform, which in the
    pre-ref-counting era had the sole ownership on the profiles.

diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index fb8cb37a..2fb78c1c 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -216,51 +216,10 @@ GfxColorTransform::GfxColorTransform(const GfxLCMSProfilePtr& sourceProfileA, vo
   cmsIntent = cmsIntentA;
   inputPixelType = inputPixelTypeA;
   transformPixelType = transformPixelTypeA;
-  psCSA = nullptr;
 }
 
 GfxColorTransform::~GfxColorTransform() {
   cmsDeleteTransform(transform);
-  if (psCSA)
-    gfree(psCSA);
-}
-
-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)
-    return psCSA;
-
-  if (!sourceProfile) {
-    error(errSyntaxWarning, -1, "profile is nullptr");
-    return nullptr;
-  }
-
-  void *rawprofile = sourceProfile.get();
-  size = cmsGetPostScriptCSA(cmsGetProfileContextID(rawprofile), rawprofile, cmsIntent, 0, nullptr, 0);
-  if (size == 0) {
-    error(errSyntaxWarning, -1, "PostScript CSA is nullptr");
-    return nullptr;
-  }
-
-  psCSA = (char*)gmalloc(size+1);
-  cmsGetPostScriptCSA(cmsGetProfileContextID(rawprofile), rawprofile, cmsIntent, 0, psCSA, size);
-  psCSA[size] = 0;
-
-  return psCSA;
-#else
-  return nullptr;
-#endif
 }
 
 static GfxLCMSProfilePtr RGBProfile = nullptr;
@@ -1758,11 +1717,16 @@ GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
 #ifdef USE_CMS
   transform = nullptr;
   lineTransform = nullptr;
+  psCSA = nullptr;
 #endif
 }
 
 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
   delete alt;
+#ifdef USE_CMS
+  if (psCSA)
+    gfree(psCSA);
+#endif
 }
 
 GfxColorSpace *GfxICCBasedColorSpace::copy() const {
@@ -1870,6 +1834,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
 
   profBuf = iccStream->toUnsignedChars(&length, 65536, 65536);
   auto hp = make_GfxLCMSProfilePtr(cmsOpenProfileFromMem(profBuf,length));
+  cs->profile = hp;
   gfree(profBuf);
   if (!hp) {
     error(errSyntaxWarning, -1, "read ICCBased color space profile error");
@@ -2366,10 +2331,40 @@ void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
 #ifdef USE_CMS
 char *GfxICCBasedColorSpace::getPostScriptCSA()
 {
-  if (transform)
-    return transform->getPostScriptCSA();
-  else
+#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)
+    return psCSA;
+
+  if (!profile) {
+    error(errSyntaxWarning, -1, "profile is nullptr");
+    return nullptr;
+  }
+
+  void *rawprofile = profile.get();
+  size = cmsGetPostScriptCSA(cmsGetProfileContextID(rawprofile), rawprofile, getIntent(), 0, nullptr, 0);
+  if (size == 0) {
+    error(errSyntaxWarning, -1, "PostScript CSA is nullptr");
+    return nullptr;
+  }
+
+  psCSA = (char*)gmalloc(size+1);
+  cmsGetPostScriptCSA(cmsGetProfileContextID(rawprofile), rawprofile, getIntent(), 0, psCSA, size);
+  psCSA[size] = 0;
+
+  return psCSA;
+#else
+  return nullptr;
+#endif
 }
 #endif
 
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 1a673b20..f79c6bc7 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -213,7 +213,6 @@ public:
   int getInputPixelType() const { return inputPixelType; }
   int getTransformPixelType() const { return transformPixelType; }
   GfxLCMSProfilePtr getSourceProfile() { return sourceProfile; }
-  char *getPostScriptCSA();
 private:
   GfxColorTransform() {}
   GfxLCMSProfilePtr sourceProfile;
@@ -221,7 +220,6 @@ private:
   int cmsIntent;
   unsigned int inputPixelType;
   unsigned int transformPixelType;
-  char *psCSA;
 };
 
 class GfxColorSpace {
@@ -582,6 +580,7 @@ public:
   Ref getRef() { return iccProfileStream; }
 #ifdef USE_CMS
   char *getPostScriptCSA();
+  GfxLCMSProfilePtr getProfile() { return profile; }
 #endif
 
 private:
@@ -592,6 +591,8 @@ private:
   double rangeMax[4];		// max values for each component
   Ref iccProfileStream;		// the ICC profile
 #ifdef USE_CMS
+  GfxLCMSProfilePtr profile;
+  char* psCSA;
   int getIntent() { return (transform != nullptr) ? transform->getIntent() : 0; }
   std::shared_ptr<GfxColorTransform> transform;
   std::shared_ptr<GfxColorTransform> lineTransform; // color transform for line


More information about the poppler mailing list