[poppler] 5 commits - poppler/Gfx.cc poppler/GfxState.cc poppler/GfxState.h poppler/OutputDev.h poppler/PSOutputDev.cc utils/CMakeLists.txt utils/pdftoppm.1 utils/pdftoppm.cc utils/pdftops.1 utils/pdftops.cc utils/sanitychecks.cc utils/sanitychecks.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sat Dec 26 23:46:21 UTC 2020


 poppler/Gfx.cc         |   12 ++--
 poppler/GfxState.cc    |  123 ++++++++++++++++++++++++++++++-------------------
 poppler/GfxState.h     |   36 ++++++++++++++
 poppler/OutputDev.h    |   34 +++++++++++++
 poppler/PSOutputDev.cc |   11 +++-
 utils/CMakeLists.txt   |    2 
 utils/pdftoppm.1       |   12 ++++
 utils/pdftoppm.cc      |   47 ++++++++++++++++--
 utils/pdftops.1        |   12 ++++
 utils/pdftops.cc       |   50 +++++++++++++++++--
 utils/sanitychecks.cc  |   52 ++++++++++++++++++++
 utils/sanitychecks.h   |   30 +++++++++++
 12 files changed, 358 insertions(+), 63 deletions(-)

New commits:
commit 94fea737473dd513438b7fb89347c6f1273e61b3
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Wed Dec 2 01:04:47 2020 +0100

    pdftoppm/pdftops: move shared ICC profile checks to their own file

diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index a5951795..32fbcb48 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -11,6 +11,7 @@ if (ENABLE_SPLASH)
   # pdftoppm
   set(pdftoppm_SOURCES ${common_srcs}
     pdftoppm.cc
+    sanitychecks.cc
   )
   add_executable(pdftoppm ${pdftoppm_SOURCES})
   target_link_libraries(pdftoppm ${common_libs})
@@ -111,6 +112,7 @@ endif ()
 # pdftops
 set(pdftops_SOURCES ${common_srcs}
   pdftops.cc
+  sanitychecks.cc
 )
 add_executable(pdftops ${pdftops_SOURCES})
 target_link_libraries(pdftops ${common_libs})
diff --git a/utils/pdftoppm.cc b/utils/pdftoppm.cc
index 344c83ec..57bf8614 100644
--- a/utils/pdftoppm.cc
+++ b/utils/pdftoppm.cc
@@ -61,6 +61,7 @@
 #include "SplashOutputDev.h"
 #include "Win32Console.h"
 #include "numberofcharacters.h"
+#include "sanitychecks.h"
 
 // Uncomment to build pdftoppm with pthreads
 // You may also have to change the buildsystem to
@@ -546,6 +547,9 @@ int main(int argc, char *argv[])
             goto err1;
         }
         profilecolorspace = cmsGetColorSpace(displayprofile.get());
+        // Note: In contrast to pdftops we do not fail if a non-matching ICC profile is supplied.
+        //       Doing so would be pretentious, since SplashOutputDev by default assumes sRGB, even for
+        //       the CMYK and Mono cases.
         if (jpegcmyk || overprint) {
             if (profilecolorspace != cmsSigCmykData) {
                 fprintf(stderr, "Warning: Supplied ICC profile \"%s\" is not a CMYK profile.\n", displayprofilename.c_str());
@@ -562,52 +566,19 @@ int main(int argc, char *argv[])
     }
     if (!defaultgrayprofilename.toStr().empty()) {
         defaultgrayprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultgrayprofilename.c_str(), "r"));
-        if (!defaultgrayprofile) {
-            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultgrayprofilename.c_str());
-            goto err1;
-        }
-        if (!cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
-            && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
-            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultgrayprofilename.c_str());
-            goto err1;
-        }
-        profilecolorspace = cmsGetColorSpace(defaultgrayprofile.get());
-        if (profilecolorspace != cmsSigGrayData) {
-            fprintf(stderr, "Supplied ICC profile \"%s\" is not a monochrome profile.\n", defaultgrayprofilename.c_str());
+        if (!checkICCProfile(defaultgrayprofile, defaultgrayprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigGrayData)) {
             goto err1;
         }
     }
     if (!defaultrgbprofilename.toStr().empty()) {
         defaultrgbprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultrgbprofilename.c_str(), "r"));
-        if (!defaultrgbprofile) {
-            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultrgbprofilename.c_str());
-            goto err1;
-        }
-        if (!cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
-            && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
-            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultrgbprofilename.c_str());
-            goto err1;
-        }
-        profilecolorspace = cmsGetColorSpace(defaultrgbprofile.get());
-        if (profilecolorspace != cmsSigRgbData) {
-            fprintf(stderr, "Supplied ICC profile \"%s\" is not a RGB profile.\n", defaultrgbprofilename.c_str());
+        if (!checkICCProfile(defaultrgbprofile, defaultrgbprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigRgbData)) {
             goto err1;
         }
     }
     if (!defaultcmykprofilename.toStr().empty()) {
         defaultcmykprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultcmykprofilename.c_str(), "r"));
-        if (!defaultcmykprofile) {
-            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultcmykprofilename.c_str());
-            goto err1;
-        }
-        if (!cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
-            && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
-            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultcmykprofilename.c_str());
-            goto err1;
-        }
-        profilecolorspace = cmsGetColorSpace(defaultcmykprofile.get());
-        if (profilecolorspace != cmsSigCmykData) {
-            fprintf(stderr, "Supplied ICC profile \"%s\" is not a CMYK profile.\n", defaultcmykprofilename.c_str());
+        if (!checkICCProfile(defaultcmykprofile, defaultcmykprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigCmykData)) {
             goto err1;
         }
     }
diff --git a/utils/pdftops.cc b/utils/pdftops.cc
index e380726a..597a7937 100644
--- a/utils/pdftops.cc
+++ b/utils/pdftops.cc
@@ -55,6 +55,7 @@
 #include "PSOutputDev.h"
 #include "Error.h"
 #include "Win32Console.h"
+#include "sanitychecks.h"
 
 #ifdef USE_CMS
 #    include <lcms2.h>
@@ -359,52 +360,19 @@ int main(int argc, char *argv[])
 #ifdef USE_CMS
     if (!defaultgrayprofilename.toStr().empty()) {
         defaultgrayprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultgrayprofilename.c_str(), "r"));
-        if (!defaultgrayprofile) {
-            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultgrayprofilename.c_str());
-            goto err05;
-        }
-        if (!cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
-            && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
-            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultgrayprofilename.c_str());
-            goto err05;
-        }
-        profilecolorspace = cmsGetColorSpace(defaultgrayprofile.get());
-        if (profilecolorspace != cmsSigGrayData) {
-            fprintf(stderr, "Supplied ICC profile \"%s\" is not a monochrome profile.\n", defaultgrayprofilename.c_str());
+        if (!checkICCProfile(defaultgrayprofile, defaultgrayprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigGrayData)) {
             goto err05;
         }
     }
     if (!defaultrgbprofilename.toStr().empty()) {
         defaultrgbprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultrgbprofilename.c_str(), "r"));
-        if (!defaultrgbprofile) {
-            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultrgbprofilename.c_str());
-            goto err05;
-        }
-        if (!cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
-            && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
-            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultrgbprofilename.c_str());
-            goto err05;
-        }
-        profilecolorspace = cmsGetColorSpace(defaultrgbprofile.get());
-        if (profilecolorspace != cmsSigRgbData) {
-            fprintf(stderr, "Supplied ICC profile \"%s\" is not a RGB profile.\n", defaultrgbprofilename.c_str());
+        if (!checkICCProfile(defaultrgbprofile, defaultrgbprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigRgbData)) {
             goto err05;
         }
     }
     if (!defaultcmykprofilename.toStr().empty()) {
         defaultcmykprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultcmykprofilename.c_str(), "r"));
-        if (!defaultcmykprofile) {
-            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultcmykprofilename.c_str());
-            goto err05;
-        }
-        if (!cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
-            && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
-            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultcmykprofilename.c_str());
-            goto err05;
-        }
-        profilecolorspace = cmsGetColorSpace(defaultcmykprofile.get());
-        if (profilecolorspace != cmsSigCmykData) {
-            fprintf(stderr, "Supplied ICC profile \"%s\" is not a CMYK profile.\n", defaultcmykprofilename.c_str());
+        if (!checkICCProfile(defaultcmykprofile, defaultcmykprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigCmykData)) {
             goto err05;
         }
     }
diff --git a/utils/sanitychecks.cc b/utils/sanitychecks.cc
new file mode 100644
index 00000000..1bcdeb72
--- /dev/null
+++ b/utils/sanitychecks.cc
@@ -0,0 +1,52 @@
+//========================================================================
+//
+// sanitychecks.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright (C) 2020 Philipp Knechtges <philipp-dev at knechtges.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <cstdio>
+#include <cstddef>
+#include <cstring>
+#include <cstdlib>
+#include <cctype>
+#include "sanitychecks.h"
+
+#ifdef USE_CMS
+bool checkICCProfile(const GfxLCMSProfilePtr &profile, const char *filename, cmsUInt32Number UsedDirection, cmsColorSpaceSignature expectedColorSpace)
+{
+    if (!profile) {
+        fprintf(stderr, "Could not open the ICC profile \"%s\".\n", filename);
+        return false;
+    }
+    if (!cmsIsIntentSupported(profile.get(), INTENT_RELATIVE_COLORIMETRIC, UsedDirection) && !cmsIsIntentSupported(profile.get(), INTENT_ABSOLUTE_COLORIMETRIC, UsedDirection)
+        && !cmsIsIntentSupported(profile.get(), INTENT_SATURATION, UsedDirection) && !cmsIsIntentSupported(profile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT)) {
+        if (UsedDirection == LCMS_USED_AS_OUTPUT) {
+            fprintf(stderr, "ICC profile \"%s\" is not an output profile.\n", filename);
+        } else if (UsedDirection == LCMS_USED_AS_INPUT) {
+            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", filename);
+        } else {
+            fprintf(stderr, "ICC profile \"%s\" is not suitable.\n", filename);
+        }
+        return false;
+    }
+    auto profilecolorspace = cmsGetColorSpace(profile.get());
+    if (profilecolorspace != expectedColorSpace) {
+        if (expectedColorSpace == cmsSigCmykData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a CMYK profile.\n", filename);
+        } else if (expectedColorSpace == cmsSigGrayData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a monochrome profile.\n", filename);
+        } else if (expectedColorSpace == cmsSigRgbData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a RGB profile.\n", filename);
+        }
+        return false;
+    }
+    return true;
+}
+#endif
diff --git a/utils/sanitychecks.h b/utils/sanitychecks.h
new file mode 100644
index 00000000..d1af2374
--- /dev/null
+++ b/utils/sanitychecks.h
@@ -0,0 +1,30 @@
+//========================================================================
+//
+// sanitychecks.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright (C) 2020 Philipp Knechtges <philipp-dev at knechtges.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SANITYCHECKS_H
+#define SANITYCHECKS_H
+
+#include "config.h"
+
+#ifdef USE_CMS
+#    include <lcms2.h>
+#    include "GfxState.h"
+
+/*
+ * Check the supplied ICC profile for different criteria
+ */
+bool checkICCProfile(const GfxLCMSProfilePtr &profile, const char *filename, cmsUInt32Number UsedDirection, cmsColorSpaceSignature expectedColorSpace);
+
+#endif
+
+#endif
commit 3ea4508575167ec67583d3ed13efa100b8985b92
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Wed Sep 30 21:40:39 2020 +0200

    pdftops: add options to set DeviceGray/DeviceRGB/DeviceCMYK to the CLI

diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index e7c0a31b..1b0bb66c 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -3211,6 +3211,9 @@ bool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/, i
     splashOut->setVectorAntialias(rasterAntialias);
 #    ifdef USE_CMS
     splashOut->setDisplayProfile(getDisplayProfile());
+    splashOut->setDefaultGrayProfile(getDefaultGrayProfile());
+    splashOut->setDefaultRGBProfile(getDefaultRGBProfile());
+    splashOut->setDefaultCMYKProfile(getDefaultCMYKProfile());
 #    endif
     splashOut->startDoc(doc);
 
diff --git a/utils/pdftops.1 b/utils/pdftops.1
index 00e19856..0ab17cbb 100644
--- a/utils/pdftops.1
+++ b/utils/pdftops.1
@@ -150,6 +150,18 @@ is given then \-processcolorformat is inferred from the specified ICC profile.
 .BI \-processcolorprofile " filename"
 Sets the ICC profile that is assumed during rasterization and transparency reduction.
 .TP
+.BI \-defaultgrayprofile " defaultgrayprofilefile"
+If poppler is compiled with colour management support, this option sets the DefaultGray color space
+to the ICC profile stored in defaultgrayprofilefile.
+.TP
+.BI \-defaultrgbprofile " defaultrgbprofilefile"
+If poppler is compiled with colour management support, this option sets the DefaultRGB color space
+to the ICC profile stored in defaultrgbprofilefile.
+.TP
+.BI \-defaultcmykprofile " defaultcmykprofilefile"
+If poppler is compiled with colour management support, this option sets the DefaultCMYK color space
+to the ICC profile stored in defaultcmykprofilefile.
+.TP
 .B \-optimizecolorspace
 By default, bitmap images in the PDF pass through to the output PostScript
 in their original color space, which produces predictable results.
diff --git a/utils/pdftops.cc b/utils/pdftops.cc
index 5b844444..e380726a 100644
--- a/utils/pdftops.cc
+++ b/utils/pdftops.cc
@@ -131,6 +131,14 @@ static GooString processcolorprofilename;
 static GfxLCMSProfilePtr processcolorprofile;
 #    endif
 #endif
+#ifdef USE_CMS
+static GooString defaultgrayprofilename;
+static GfxLCMSProfilePtr defaultgrayprofile;
+static GooString defaultrgbprofilename;
+static GfxLCMSProfilePtr defaultrgbprofile;
+static GooString defaultcmykprofilename;
+static GfxLCMSProfilePtr defaultcmykprofile;
+#endif
 
 static const ArgDesc argDesc[] = { { "-f", argInt, &firstPage, 0, "first page to print" },
                                    { "-l", argInt, &lastPage, 0, "last page to print" },
@@ -160,6 +168,11 @@ static const ArgDesc argDesc[] = { { "-f", argInt, &firstPage, 0, "first page to
 #    ifdef USE_CMS
                                    { "-processcolorprofile", argGooString, &processcolorprofilename, 0, "ICC color profile to use as the process color profile during rasterization and transparency reduction" },
 #    endif
+#endif
+#ifdef USE_CMS
+                                   { "-defaultgrayprofile", argGooString, &defaultgrayprofilename, 0, "ICC color profile to use as the DefaultGray color space" },
+                                   { "-defaultrgbprofile", argGooString, &defaultrgbprofilename, 0, "ICC color profile to use as the DefaultRGB color space" },
+                                   { "-defaultcmykprofile", argGooString, &defaultcmykprofilename, 0, "ICC color profile to use as the DefaultCMYK color space" },
 #endif
                                    { "-optimizecolorspace", argFlag, &optimizeColorSpace, 0, "convert gray RGB images to gray color space" },
                                    { "-passlevel1customcolor", argFlag, &passLevel1CustomColor, 0, "pass custom color in level1sep" },
@@ -197,7 +210,7 @@ int main(int argc, char *argv[])
     bool rasterAntialias = false;
     std::vector<int> pages;
 #ifdef USE_CMS
-    cmsColorSpaceSignature displayprofilecolorspace;
+    cmsColorSpaceSignature profilecolorspace;
 #endif
 
     Win32Console win32Console(&argc, &argv);
@@ -303,8 +316,8 @@ int main(int argc, char *argv[])
             fprintf(stderr, "Error: ICC profile \"%s\" is not an output profile.\n", processcolorprofilename.c_str());
             goto err05;
         }
-        displayprofilecolorspace = cmsGetColorSpace(processcolorprofile.get());
-        if (displayprofilecolorspace == cmsSigCmykData) {
+        profilecolorspace = cmsGetColorSpace(processcolorprofile.get());
+        if (profilecolorspace == cmsSigCmykData) {
             if (!processcolorformatspecified) {
                 processcolorformat = splashModeCMYK8;
                 processcolorformatspecified = true;
@@ -312,7 +325,7 @@ int main(int argc, char *argv[])
                 fprintf(stderr, "Error: Supplied ICC profile \"%s\" is a CMYK profile, but process color format is not CMYK8.\n", processcolorprofilename.c_str());
                 goto err05;
             }
-        } else if (displayprofilecolorspace == cmsSigGrayData) {
+        } else if (profilecolorspace == cmsSigGrayData) {
             if (!processcolorformatspecified) {
                 processcolorformat = splashModeMono8;
                 processcolorformatspecified = true;
@@ -320,7 +333,7 @@ int main(int argc, char *argv[])
                 fprintf(stderr, "Error: Supplied ICC profile \"%s\" is a monochrome profile, but process color format is not monochrome.\n", processcolorprofilename.c_str());
                 goto err05;
             }
-        } else if (displayprofilecolorspace == cmsSigRgbData) {
+        } else if (profilecolorspace == cmsSigRgbData) {
             if (!processcolorformatspecified) {
                 processcolorformat = splashModeRGB8;
                 processcolorformatspecified = true;
@@ -343,6 +356,60 @@ int main(int argc, char *argv[])
     }
 #endif
 
+#ifdef USE_CMS
+    if (!defaultgrayprofilename.toStr().empty()) {
+        defaultgrayprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultgrayprofilename.c_str(), "r"));
+        if (!defaultgrayprofile) {
+            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultgrayprofilename.c_str());
+            goto err05;
+        }
+        if (!cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
+            && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
+            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultgrayprofilename.c_str());
+            goto err05;
+        }
+        profilecolorspace = cmsGetColorSpace(defaultgrayprofile.get());
+        if (profilecolorspace != cmsSigGrayData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a monochrome profile.\n", defaultgrayprofilename.c_str());
+            goto err05;
+        }
+    }
+    if (!defaultrgbprofilename.toStr().empty()) {
+        defaultrgbprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultrgbprofilename.c_str(), "r"));
+        if (!defaultrgbprofile) {
+            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultrgbprofilename.c_str());
+            goto err05;
+        }
+        if (!cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
+            && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
+            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultrgbprofilename.c_str());
+            goto err05;
+        }
+        profilecolorspace = cmsGetColorSpace(defaultrgbprofile.get());
+        if (profilecolorspace != cmsSigRgbData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a RGB profile.\n", defaultrgbprofilename.c_str());
+            goto err05;
+        }
+    }
+    if (!defaultcmykprofilename.toStr().empty()) {
+        defaultcmykprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultcmykprofilename.c_str(), "r"));
+        if (!defaultcmykprofile) {
+            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultcmykprofilename.c_str());
+            goto err05;
+        }
+        if (!cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
+            && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
+            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultcmykprofilename.c_str());
+            goto err05;
+        }
+        profilecolorspace = cmsGetColorSpace(defaultcmykprofile.get());
+        if (profilecolorspace != cmsSigCmykData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a CMYK profile.\n", defaultcmykprofilename.c_str());
+            goto err05;
+        }
+    }
+#endif
+
     // open PDF file
     if (ownerPassword[0] != '\001') {
         ownerPW = new GooString(ownerPassword);
@@ -455,6 +522,11 @@ int main(int argc, char *argv[])
 #    ifdef USE_CMS
     psOut->setDisplayProfile(processcolorprofile);
 #    endif
+#endif
+#ifdef USE_CMS
+    psOut->setDefaultGrayProfile(defaultgrayprofile);
+    psOut->setDefaultRGBProfile(defaultrgbprofile);
+    psOut->setDefaultCMYKProfile(defaultcmykprofile);
 #endif
     psOut->setEmbedType1(!noEmbedT1Fonts);
     psOut->setEmbedTrueType(!noEmbedTTFonts);
commit 66eab5dab46d84b11d3eaa3ee107cb370061e39e
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Wed Sep 30 21:39:19 2020 +0200

    PSOutputDev: allow ICCBased color spaces with invalid Ref to be embedded

diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 4eeaf7b3..e7c0a31b 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -6592,8 +6592,14 @@ void PSOutputDev::dumpColorSpaceL2(GfxState *state, GfxColorSpace *colorSpace, b
         GfxICCBasedColorSpace *iccBasedCS;
         iccBasedCS = (GfxICCBasedColorSpace *)colorSpace;
         Ref ref = iccBasedCS->getRef();
+        const bool validref = ref != Ref::INVALID();
         int intent = state->getCmsRenderingIntent();
-        GooString *name = GooString::format("ICCBased-{0:d}-{1:d}-{2:d}", ref.num, ref.gen, intent);
+        GooString *name;
+        if (validref) {
+            name = GooString::format("ICCBased-{0:d}-{1:d}-{2:d}", ref.num, ref.gen, intent);
+        } else {
+            name = GooString::format("ICCBased-hashed-{0:ullX}-{1:d}", std::hash<GfxLCMSProfilePtr> {}(iccBasedCS->getProfile()), intent);
+        }
         const auto &it = iccEmitted.find(name->toStr());
         if (it != iccEmitted.end()) {
             writePSFmt("{0:t}", name);
commit 0d6a3dd991efff3126a1cb9b4de21a2c6db6fb45
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Wed Sep 30 15:47:06 2020 +0200

    pdftoppm: add options to set DeviceGray/DeviceRGB/DeviceCMYK to the CLI

diff --git a/utils/pdftoppm.1 b/utils/pdftoppm.1
index 08c3a284..2cd52b19 100644
--- a/utils/pdftoppm.1
+++ b/utils/pdftoppm.1
@@ -98,6 +98,18 @@ Generate a grayscale PGM file (instead of a color PPM file).
 If poppler is compiled with colour management support, this option sets the display profile
 to the ICC profile stored in displayprofilefile.
 .TP
+.BI \-defaultgrayprofile " defaultgrayprofilefile"
+If poppler is compiled with colour management support, this option sets the DefaultGray color space
+to the ICC profile stored in defaultgrayprofilefile.
+.TP
+.BI \-defaultrgbprofile " defaultrgbprofilefile"
+If poppler is compiled with colour management support, this option sets the DefaultRGB color space
+to the ICC profile stored in defaultrgbprofilefile.
+.TP
+.BI \-defaultcmykprofile " defaultcmykprofilefile"
+If poppler is compiled with colour management support, this option sets the DefaultCMYK color space
+to the ICC profile stored in defaultcmykprofilefile.
+.TP
 .B \-png
 Generates a PNG file instead a PPM file.
 .TP
diff --git a/utils/pdftoppm.cc b/utils/pdftoppm.cc
index 4e3f1e67..344c83ec 100644
--- a/utils/pdftoppm.cc
+++ b/utils/pdftoppm.cc
@@ -102,6 +102,12 @@ static bool gray = false;
 #ifdef USE_CMS
 static GooString displayprofilename;
 static GfxLCMSProfilePtr displayprofile;
+static GooString defaultgrayprofilename;
+static GfxLCMSProfilePtr defaultgrayprofile;
+static GooString defaultrgbprofilename;
+static GfxLCMSProfilePtr defaultrgbprofile;
+static GooString defaultcmykprofilename;
+static GfxLCMSProfilePtr defaultcmykprofile;
 #endif
 static char sep[2] = "-";
 static bool forceNum = false;
@@ -158,6 +164,9 @@ static const ArgDesc argDesc[] = { { "-f", argInt, &firstPage, 0, "first page to
                                    { "-gray", argFlag, &gray, 0, "generate a grayscale PGM file" },
 #ifdef USE_CMS
                                    { "-displayprofile", argGooString, &displayprofilename, 0, "ICC color profile to use as the display profile" },
+                                   { "-defaultgrayprofile", argGooString, &defaultgrayprofilename, 0, "ICC color profile to use as the DefaultGray color space" },
+                                   { "-defaultrgbprofile", argGooString, &defaultrgbprofilename, 0, "ICC color profile to use as the DefaultRGB color space" },
+                                   { "-defaultcmykprofile", argGooString, &defaultcmykprofilename, 0, "ICC color profile to use as the DefaultCMYK color space" },
 #endif
                                    { "-sep", argString, sep, sizeof(sep), "single character separator between name and page number, default - " },
                                    { "-forcenum", argFlag, &forceNum, 0, "force page number even if there is only one page " },
@@ -353,6 +362,9 @@ static void processPageJobs()
         splashOut->setEnableFreeType(enableFreeType);
 #    ifdef USE_CMS
         splashOut->setDisplayProfile(displayprofile);
+        splashOut->setDefaultGrayProfile(defaultgrayprofile);
+        splashOut->setDefaultRGBProfile(defaultrgbprofile);
+        splashOut->setDefaultCMYKProfile(defaultcmykprofile);
 #    endif
         splashOut->startDoc(pageJob.doc);
 
@@ -383,7 +395,7 @@ int main(int argc, char *argv[])
     int pg, pg_num_len;
     double pg_w, pg_h;
 #ifdef USE_CMS
-    cmsColorSpaceSignature displayprofilecolorspace;
+    cmsColorSpaceSignature profilecolorspace;
 #endif
 
     Win32Console win32Console(&argc, &argv);
@@ -533,21 +545,72 @@ int main(int argc, char *argv[])
             fprintf(stderr, "ICC profile \"%s\" is not an output profile.\n", displayprofilename.c_str());
             goto err1;
         }
-        displayprofilecolorspace = cmsGetColorSpace(displayprofile.get());
+        profilecolorspace = cmsGetColorSpace(displayprofile.get());
         if (jpegcmyk || overprint) {
-            if (displayprofilecolorspace != cmsSigCmykData) {
+            if (profilecolorspace != cmsSigCmykData) {
                 fprintf(stderr, "Warning: Supplied ICC profile \"%s\" is not a CMYK profile.\n", displayprofilename.c_str());
             }
         } else if (mono || gray) {
-            if (displayprofilecolorspace != cmsSigGrayData) {
+            if (profilecolorspace != cmsSigGrayData) {
                 fprintf(stderr, "Warning: Supplied ICC profile \"%s\" is not a monochrome profile.\n", displayprofilename.c_str());
             }
         } else {
-            if (displayprofilecolorspace != cmsSigRgbData) {
+            if (profilecolorspace != cmsSigRgbData) {
                 fprintf(stderr, "Warning: Supplied ICC profile \"%s\" is not a RGB profile.\n", displayprofilename.c_str());
             }
         }
     }
+    if (!defaultgrayprofilename.toStr().empty()) {
+        defaultgrayprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultgrayprofilename.c_str(), "r"));
+        if (!defaultgrayprofile) {
+            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultgrayprofilename.c_str());
+            goto err1;
+        }
+        if (!cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
+            && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultgrayprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
+            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultgrayprofilename.c_str());
+            goto err1;
+        }
+        profilecolorspace = cmsGetColorSpace(defaultgrayprofile.get());
+        if (profilecolorspace != cmsSigGrayData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a monochrome profile.\n", defaultgrayprofilename.c_str());
+            goto err1;
+        }
+    }
+    if (!defaultrgbprofilename.toStr().empty()) {
+        defaultrgbprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultrgbprofilename.c_str(), "r"));
+        if (!defaultrgbprofile) {
+            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultrgbprofilename.c_str());
+            goto err1;
+        }
+        if (!cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
+            && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultrgbprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
+            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultrgbprofilename.c_str());
+            goto err1;
+        }
+        profilecolorspace = cmsGetColorSpace(defaultrgbprofile.get());
+        if (profilecolorspace != cmsSigRgbData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a RGB profile.\n", defaultrgbprofilename.c_str());
+            goto err1;
+        }
+    }
+    if (!defaultcmykprofilename.toStr().empty()) {
+        defaultcmykprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultcmykprofilename.c_str(), "r"));
+        if (!defaultcmykprofile) {
+            fprintf(stderr, "Could not open the ICC profile \"%s\".\n", defaultcmykprofilename.c_str());
+            goto err1;
+        }
+        if (!cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_INPUT)
+            && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_SATURATION, LCMS_USED_AS_INPUT) && !cmsIsIntentSupported(defaultcmykprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
+            fprintf(stderr, "ICC profile \"%s\" is not an input profile.\n", defaultcmykprofilename.c_str());
+            goto err1;
+        }
+        profilecolorspace = cmsGetColorSpace(defaultcmykprofile.get());
+        if (profilecolorspace != cmsSigCmykData) {
+            fprintf(stderr, "Supplied ICC profile \"%s\" is not a CMYK profile.\n", defaultcmykprofilename.c_str());
+            goto err1;
+        }
+    }
 #endif
 
 #ifndef UTILS_USE_PTHREADS
@@ -559,6 +622,9 @@ int main(int argc, char *argv[])
     splashOut->setEnableFreeType(enableFreeType);
 #    ifdef USE_CMS
     splashOut->setDisplayProfile(displayprofile);
+    splashOut->setDefaultGrayProfile(defaultgrayprofile);
+    splashOut->setDefaultRGBProfile(defaultrgbprofile);
+    splashOut->setDefaultCMYKProfile(defaultcmykprofile);
 #    endif
     splashOut->startDoc(doc);
 
commit 1feeda46eb7c02092855c8d609cd493d9cfee18a
Author: Philipp Knechtges <philipp-dev at knechtges.com>
Date:   Wed Sep 30 13:56:43 2020 +0200

    Introduce options to set fallback DefaultGray/DefaultRGB/DefaultCMYK color spaces to ICC profiles
    
    This will allow for a fully color-managed workflow in cases where the pdf does not specify default
    color spaces.

diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 746703ab..78adcf79 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -1315,7 +1315,7 @@ void Gfx::opSetFillGray(Object args[], int numArgs)
         colorSpace = GfxColorSpace::parse(res, &obj, out, state);
     }
     if (colorSpace == nullptr) {
-        colorSpace = new GfxDeviceGrayColorSpace();
+        colorSpace = state->copyDefaultGrayColorSpace();
     }
     state->setFillColorSpace(colorSpace);
     out->updateFillColorSpace(state);
@@ -1335,7 +1335,7 @@ void Gfx::opSetStrokeGray(Object args[], int numArgs)
         colorSpace = GfxColorSpace::parse(res, &obj, out, state);
     }
     if (colorSpace == nullptr) {
-        colorSpace = new GfxDeviceGrayColorSpace();
+        colorSpace = state->copyDefaultGrayColorSpace();
     }
     state->setStrokeColorSpace(colorSpace);
     out->updateStrokeColorSpace(state);
@@ -1355,7 +1355,7 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs)
         colorSpace = GfxColorSpace::parse(res, &obj, out, state);
     }
     if (colorSpace == nullptr) {
-        colorSpace = new GfxDeviceCMYKColorSpace();
+        colorSpace = state->copyDefaultCMYKColorSpace();
     }
     state->setFillPattern(nullptr);
     state->setFillColorSpace(colorSpace);
@@ -1379,7 +1379,7 @@ void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs)
         colorSpace = GfxColorSpace::parse(res, &obj, out, state);
     }
     if (colorSpace == nullptr) {
-        colorSpace = new GfxDeviceCMYKColorSpace();
+        colorSpace = state->copyDefaultCMYKColorSpace();
     }
     state->setStrokeColorSpace(colorSpace);
     out->updateStrokeColorSpace(state);
@@ -1402,7 +1402,7 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs)
         colorSpace = GfxColorSpace::parse(res, &obj, out, state);
     }
     if (colorSpace == nullptr) {
-        colorSpace = new GfxDeviceRGBColorSpace();
+        colorSpace = state->copyDefaultRGBColorSpace();
     }
     state->setFillColorSpace(colorSpace);
     out->updateFillColorSpace(state);
@@ -1425,7 +1425,7 @@ void Gfx::opSetStrokeRGBColor(Object args[], int numArgs)
         colorSpace = GfxColorSpace::parse(res, &obj, out, state);
     }
     if (colorSpace == nullptr) {
-        colorSpace = new GfxDeviceRGBColorSpace();
+        colorSpace = state->copyDefaultRGBColorSpace();
     }
     state->setStrokeColorSpace(colorSpace);
     out->updateStrokeColorSpace(state);
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index da040dd0..cffa7c43 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -234,34 +234,34 @@ GfxColorSpace *GfxColorSpace::parse(GfxResources *res, Object *csObj, OutputDev
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultGray");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceGrayColorSpace();
+                    cs = state->copyDefaultGrayColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceGrayColorSpace();
+                cs = state->copyDefaultGrayColorSpace();
             }
         } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultRGB");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceRGBColorSpace();
+                    cs = state->copyDefaultRGBColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceRGBColorSpace();
+                cs = state->copyDefaultRGBColorSpace();
             }
         } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultCMYK");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceCMYKColorSpace();
+                    cs = state->copyDefaultCMYKColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceCMYKColorSpace();
+                cs = state->copyDefaultCMYKColorSpace();
             }
         } else if (csObj->isName("Pattern")) {
             cs = new GfxPatternColorSpace(nullptr);
@@ -274,34 +274,34 @@ GfxColorSpace *GfxColorSpace::parse(GfxResources *res, Object *csObj, OutputDev
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultGray");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceGrayColorSpace();
+                    cs = state->copyDefaultGrayColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceGrayColorSpace();
+                cs = state->copyDefaultGrayColorSpace();
             }
         } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultRGB");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceRGBColorSpace();
+                    cs = state->copyDefaultRGBColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceRGBColorSpace();
+                cs = state->copyDefaultRGBColorSpace();
             }
         } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultCMYK");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceCMYKColorSpace();
+                    cs = state->copyDefaultCMYKColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceCMYKColorSpace();
+                cs = state->copyDefaultCMYKColorSpace();
             }
         } else if (obj1.isName("CalGray")) {
             cs = GfxCalGrayColorSpace::parse(csObj->getArray(), state);
@@ -328,34 +328,34 @@ GfxColorSpace *GfxColorSpace::parse(GfxResources *res, Object *csObj, OutputDev
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultGray");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceGrayColorSpace();
+                    cs = state->copyDefaultGrayColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceGrayColorSpace();
+                cs = state->copyDefaultGrayColorSpace();
             }
         } else if (obj1.isName("DeviceRGB")) {
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultRGB");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceRGBColorSpace();
+                    cs = state->copyDefaultRGBColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceRGBColorSpace();
+                cs = state->copyDefaultRGBColorSpace();
             }
         } else if (obj1.isName("DeviceCMYK")) {
             if (res != nullptr) {
                 Object objCS = res->lookupColorSpace("DefaultCMYK");
                 if (objCS.isNull()) {
-                    cs = new GfxDeviceCMYKColorSpace();
+                    cs = state->copyDefaultCMYKColorSpace();
                 } else {
                     cs = GfxColorSpace::parse(nullptr, &objCS, out, state);
                 }
             } else {
-                cs = new GfxDeviceCMYKColorSpace();
+                cs = state->copyDefaultCMYKColorSpace();
             }
         } else {
             error(errSyntaxWarning, -1, "Bad color space dict'");
@@ -1724,34 +1724,7 @@ 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() : nullptr;
-        if (!dhp) {
-            dhp = GfxState::sRGBProfile;
-        }
-        unsigned int cst = getCMSColorSpaceType(cmsGetColorSpace(hp.get()));
-        unsigned int dNChannels = getCMSNChannels(cmsGetColorSpace(dhp.get()));
-        unsigned int dcst = getCMSColorSpaceType(cmsGetColorSpace(dhp.get()));
-        cmsHTRANSFORM transform;
-
-        int cmsIntent = INTENT_RELATIVE_COLORIMETRIC;
-        if (state != nullptr) {
-            cmsIntent = state->getCmsRenderingIntent();
-        }
-        if ((transform = cmsCreateTransform(hp.get(), COLORSPACE_SH(cst) | CHANNELS_SH(nCompsA) | BYTES_SH(1), dhp.get(), COLORSPACE_SH(dcst) | CHANNELS_SH(dNChannels) | BYTES_SH(1), cmsIntent, LCMS_FLAGS)) == nullptr) {
-            error(errSyntaxWarning, -1, "Can't create transform");
-            cs->transform = nullptr;
-        } else {
-            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
-            if ((transform = cmsCreateTransform(hp.get(), CHANNELS_SH(nCompsA) | BYTES_SH(1), dhp.get(), (dcst == PT_RGB) ? TYPE_RGB_8 : TYPE_CMYK_8, cmsIntent, LCMS_FLAGS)) == nullptr) {
-                error(errSyntaxWarning, -1, "Can't create transform");
-                cs->lineTransform = nullptr;
-            } else {
-                cs->lineTransform = std::make_shared<GfxColorTransform>(transform, cmsIntent, cst, dcst);
-            }
-        }
+        cs->buildTransforms(state);
     }
     // put this colorSpace into cache
     if (out && iccProfileStreamA != Ref::INVALID()) {
@@ -1761,6 +1734,40 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, OutputDev *out, GfxState
     return cs;
 }
 
+#ifdef USE_CMS
+void GfxICCBasedColorSpace::buildTransforms(GfxState *state)
+{
+    auto dhp = (state != nullptr && state->getDisplayProfile() != nullptr) ? state->getDisplayProfile() : nullptr;
+    if (!dhp) {
+        dhp = GfxState::sRGBProfile;
+    }
+    unsigned int cst = getCMSColorSpaceType(cmsGetColorSpace(profile.get()));
+    unsigned int dNChannels = getCMSNChannels(cmsGetColorSpace(dhp.get()));
+    unsigned int dcst = getCMSColorSpaceType(cmsGetColorSpace(dhp.get()));
+    cmsHTRANSFORM transformA;
+
+    int cmsIntent = INTENT_RELATIVE_COLORIMETRIC;
+    if (state != nullptr) {
+        cmsIntent = state->getCmsRenderingIntent();
+    }
+    if ((transformA = cmsCreateTransform(profile.get(), COLORSPACE_SH(cst) | CHANNELS_SH(nComps) | BYTES_SH(1), dhp.get(), COLORSPACE_SH(dcst) | CHANNELS_SH(dNChannels) | BYTES_SH(1), cmsIntent, LCMS_FLAGS)) == nullptr) {
+        error(errSyntaxWarning, -1, "Can't create transform");
+        transform = nullptr;
+    } else {
+        transform = std::make_shared<GfxColorTransform>(transformA, cmsIntent, cst, dcst);
+    }
+    if (dcst == PT_RGB || dcst == PT_CMYK) {
+        // create line transform only when the display is RGB type color space
+        if ((transformA = cmsCreateTransform(profile.get(), CHANNELS_SH(nComps) | BYTES_SH(1), dhp.get(), (dcst == PT_RGB) ? TYPE_RGB_8 : TYPE_CMYK_8, cmsIntent, LCMS_FLAGS)) == nullptr) {
+            error(errSyntaxWarning, -1, "Can't create transform");
+            lineTransform = nullptr;
+        } else {
+            lineTransform = std::make_shared<GfxColorTransform>(transformA, cmsIntent, cst, dcst);
+        }
+    }
+}
+#endif
+
 void GfxICCBasedColorSpace::getGray(const GfxColor *color, GfxGray *gray) const
 {
 #ifdef USE_CMS
@@ -6280,6 +6287,10 @@ GfxState::GfxState(double hDPIA, double vDPIA, const PDFRectangle *pageBox, int
     renderingIntent[0] = 0;
 
     saved = nullptr;
+
+    defaultGrayColorSpace = nullptr;
+    defaultRGBColorSpace = nullptr;
+    defaultCMYKColorSpace = nullptr;
 #ifdef USE_CMS
     XYZ2DisplayTransformRelCol = nullptr;
     XYZ2DisplayTransformAbsCol = nullptr;
@@ -6329,6 +6340,10 @@ GfxState::~GfxState()
     if (font) {
         font->decRefCnt();
     }
+
+    delete defaultGrayColorSpace;
+    delete defaultRGBColorSpace;
+    delete defaultCMYKColorSpace;
 }
 
 // Used for copy();
@@ -6429,6 +6444,22 @@ GfxState::GfxState(const GfxState *state, bool copyPath)
     XYZ2DisplayTransformSat = state->XYZ2DisplayTransformSat;
     XYZ2DisplayTransformPerc = state->XYZ2DisplayTransformPerc;
 #endif
+
+    if (state->defaultGrayColorSpace) {
+        defaultGrayColorSpace = state->defaultGrayColorSpace->copy();
+    } else {
+        defaultGrayColorSpace = nullptr;
+    }
+    if (state->defaultRGBColorSpace) {
+        defaultRGBColorSpace = state->defaultRGBColorSpace->copy();
+    } else {
+        defaultRGBColorSpace = nullptr;
+    }
+    if (state->defaultCMYKColorSpace) {
+        defaultCMYKColorSpace = state->defaultCMYKColorSpace->copy();
+    } else {
+        defaultCMYKColorSpace = nullptr;
+    }
 }
 
 #ifdef USE_CMS
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 0eb4a9c3..f607dade 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -585,6 +585,8 @@ public:
     Ref getRef() { return iccProfileStream; }
 #ifdef USE_CMS
     char *getPostScriptCSA();
+    void buildTransforms(GfxState *state);
+    void setProfile(GfxLCMSProfilePtr &profileA) { profile = profileA; }
     GfxLCMSProfilePtr getProfile() { return profile; }
 #endif
 
@@ -1599,6 +1601,36 @@ public:
     static GfxLCMSProfilePtr sRGBProfile;
 #endif
 
+    void setDefaultGrayColorSpace(GfxColorSpace *cs) { defaultGrayColorSpace = cs; }
+
+    void setDefaultRGBColorSpace(GfxColorSpace *cs) { defaultRGBColorSpace = cs; }
+
+    void setDefaultCMYKColorSpace(GfxColorSpace *cs) { defaultCMYKColorSpace = cs; }
+
+    GfxColorSpace *copyDefaultGrayColorSpace()
+    {
+        if (defaultGrayColorSpace) {
+            return defaultGrayColorSpace->copy();
+        }
+        return new GfxDeviceGrayColorSpace();
+    }
+
+    GfxColorSpace *copyDefaultRGBColorSpace()
+    {
+        if (defaultRGBColorSpace) {
+            return defaultRGBColorSpace->copy();
+        }
+        return new GfxDeviceRGBColorSpace();
+    }
+
+    GfxColorSpace *copyDefaultCMYKColorSpace()
+    {
+        if (defaultCMYKColorSpace) {
+            return defaultCMYKColorSpace->copy();
+        }
+        return new GfxDeviceCMYKColorSpace();
+    }
+
     // Add to path.
     void moveTo(double x, double y) { path->moveTo(curX = x, curY = y); }
     void lineTo(double x, double y) { path->lineTo(curX = x, curY = y); }
@@ -1708,6 +1740,10 @@ private:
     std::shared_ptr<GfxColorTransform> XYZ2DisplayTransformPerc;
     static GfxLCMSProfilePtr XYZProfile;
 #endif
+
+    GfxColorSpace *defaultGrayColorSpace;
+    GfxColorSpace *defaultRGBColorSpace;
+    GfxColorSpace *defaultCMYKColorSpace;
 };
 
 #endif
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index d2a8e3c8..1802894b 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -138,6 +138,31 @@ public:
     {
 #ifdef USE_CMS
         state->setDisplayProfile(displayprofile);
+
+        auto invalidref = Ref::INVALID();
+        if (defaultGrayProfile) {
+            auto cs = new GfxICCBasedColorSpace(1, new GfxDeviceGrayColorSpace(), &invalidref);
+
+            cs->setProfile(defaultGrayProfile);
+            cs->buildTransforms(state); // needs to happen after state->setDisplayProfile has been called
+            state->setDefaultGrayColorSpace(cs);
+        }
+
+        if (defaultRGBProfile) {
+            auto cs = new GfxICCBasedColorSpace(3, new GfxDeviceRGBColorSpace(), &invalidref);
+
+            cs->setProfile(defaultRGBProfile);
+            cs->buildTransforms(state); // needs to happen after state->setDisplayProfile has been called
+            state->setDefaultRGBColorSpace(cs);
+        }
+
+        if (defaultCMYKProfile) {
+            auto cs = new GfxICCBasedColorSpace(4, new GfxDeviceCMYKColorSpace(), &invalidref);
+
+            cs->setProfile(defaultCMYKProfile);
+            cs->buildTransforms(state); // needs to happen after state->setDisplayProfile has been called
+            state->setDefaultCMYKColorSpace(cs);
+        }
 #endif
     }
 
@@ -324,6 +349,12 @@ public:
 #ifdef USE_CMS
     void setDisplayProfile(const GfxLCMSProfilePtr &profile) { displayprofile = profile; }
     GfxLCMSProfilePtr getDisplayProfile() const { return displayprofile; }
+    void setDefaultGrayProfile(const GfxLCMSProfilePtr &profile) { defaultGrayProfile = profile; }
+    GfxLCMSProfilePtr getDefaultGrayProfile() const { return defaultGrayProfile; }
+    void setDefaultRGBProfile(const GfxLCMSProfilePtr &profile) { defaultRGBProfile = profile; }
+    GfxLCMSProfilePtr getDefaultRGBProfile() const { return defaultRGBProfile; }
+    void setDefaultCMYKProfile(const GfxLCMSProfilePtr &profile) { defaultCMYKProfile = profile; }
+    GfxLCMSProfilePtr getDefaultCMYKProfile() const { return defaultCMYKProfile; }
 
     PopplerCache<Ref, GfxICCBasedColorSpace> *getIccColorSpaceCache() { return &iccColorSpaceCache; }
 #endif
@@ -335,6 +366,9 @@ private:
 
 #ifdef USE_CMS
     GfxLCMSProfilePtr displayprofile;
+    GfxLCMSProfilePtr defaultGrayProfile;
+    GfxLCMSProfilePtr defaultRGBProfile;
+    GfxLCMSProfilePtr defaultCMYKProfile;
 
     PopplerCache<Ref, GfxICCBasedColorSpace> iccColorSpaceCache;
 #endif


More information about the poppler mailing list