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 <[email protected]> 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 <[email protected]> +// +// 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 <[email protected]> +// +// 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 _______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
