[poppler] Color Management
Koji Otani
sho at bbr.jp
Thu Dec 11 21:26:27 PST 2008
Very sorry, I attached a wrong file to the previous mail.
I attached a correct file to this mail.
---------
Koji Otani.
From: Koji Otani <sho at bbr.jp>
Subject: Re: [poppler] Color Management
Date: Fri, 12 Dec 2008 14:16:40 +0900 (JST)
Message-ID: <20081212.141640.112579191.sho at bbr.jp>
sho> I'm Koji Otani.
sho>
sho> I found a mistake in my patch.
sho> (one #ifdef --> #if)
sho> So, in case not using CMS, compiling error occurs.
sho>
sho> I attached fixed patch.
sho>
sho>
sho>
sho>
sho>
sho> From: Koji Otani <sho at bbr.jp>
sho> Subject: Re: [poppler] Color Management
sho> Date: Thu, 27 Nov 2008 17:57:37 +0900 (JST)
sho> Message-ID: <20081127.175737.52202455.sho at bbr.jp>
sho>
sho> sho> Hi, All
sho> sho>
sho> sho> I made a patch to add Color Management to poppler.
sho> sho> I attached it to this mail.
sho> sho> This patch is one for current source in the GIT repository.
sho> sho>
sho> sho> I'm not a CM expert. And this patch doesn't resolve all problems.
sho> sho> But, I hope to make some progress.
sho> sho> Please try this.
sho> sho> ------------
sho> sho> Koji Otani.
sho> sho>
sho> sho> --------------
sho> sho> This patch adds Color Management feature to polper:
sho> sho> (1) Handling ICCBasedColorSpace (both V2 and V4 profiles)
sho> sho> (2) Handling CalRGB and CalGray
sho> sho>
sho> sho> This doesn't handle Rendering Intent.
sho> sho> This always renders with relative colorimetric intent (default in PDF).
sho> sho> This doesn't handle transparency.
sho> sho>
sho> sho> This uses Little cms library, so when compiling this, lcms-devel package is
sho> sho> needed. if lcms-devel package is not installed, disable this feature.
sho> sho>
sho> sho> In default, ICCBased uses builin Standard RGB,
sho> sho> Lab, CalRGB and CalGray don't use profile.
sho> sho> If you want to use other profile, put profile file to
sho> sho> $HOME/.xpdf/ColorProfiles/display.icc
sho> sho> or
sho> sho> /usr/share/poppler/ColorProfiles/display.icc
sho> sho> This profile is used by ICCBased, Lab, CalRGB, CalGray.
sho> sho> You can also change display profile from your application.
sho> sho> Before calling PDFDoc::displayPage, call
sho> sho> GfxColorSpace::setDisplayProfileName
sho> sho> or
sho> sho> GfxColorSpace::setDisplayProfile
sho> sho>
sho> sho> static void setDisplayProfile(cmsHPROFILE displayProfileA)
sho> sho> set profile handle
sho> sho> static void setDisplayProfileName(GooString *name)
sho> sho> set profile file name
sho> sho> If file name started with '/', it is handled as absolute path name.
sho> sho> Otherwise, it is handled as relative path to
sho> sho> $HOME/.xpdf/ColorProfiles/
sho> sho> and
sho> sho> /usr/share/poppler/ColorProfiles/
sho> sho> -----------
sho> sho>
sho> sho>
sho> sho> From: "Hal V. Engel" <hvengel at astound.net>
sho> sho> Subject: Re: [poppler] Color Management
sho> sho> Date: Thu, 21 Aug 2008 18:51:59 -0700
sho> sho> Message-ID: <200808211852.00098.hvengel at astound.net>
sho> sho>
sho> sho> hvengel> On Thursday 07 August 2008 06:58:13 pm Leonard Rosenthol wrote:
sho> sho> hvengel> > Correct. You'd need to make MAJOR changes to the rendering
sho> sho> hvengel> > architecture of Poppler to do proper color management - especially
sho> sho> hvengel> > where transparency is involved.
sho> sho> hvengel> >
sho> sho> hvengel> > But it would be a very good thing...
sho> sho> hvengel> >
sho> sho> hvengel> > Leonard
sho> sho> hvengel>
sho> sho> hvengel> (This is kind of long please bear with me).
sho> sho> hvengel>
sho> sho> hvengel> I have been looking at the PDF spec. and at the poppler code. Leonard is
sho> sho> hvengel> correct that the code in it's present form is not designed to support color
sho> sho> hvengel> management and it will require major changes.
sho> sho> hvengel>
sho> sho> hvengel> Some exmples:
sho> sho> hvengel>
sho> sho> hvengel> The PDF spec calls for all CIE based colorspaces (Lab, calRGB, calCMYK and
sho> sho> hvengel> ICCBased) to undergo the following transformations:
sho> sho> hvengel>
sho> sho> hvengel> original color space -> XYZ -> output color space
sho> sho> hvengel>
sho> sho> hvengel> This implies that there is clear separation between the first conversion and
sho> sho> hvengel> the second conversion and that one set of routines can handle the second
sho> sho> hvengel> conversion for all CIE based color transforms.
sho> sho> hvengel>
sho> sho> hvengel> It also implies that there is some way for calling applications to specifiy a
sho> sho> hvengel> CIE based output color space such as an ICC profile and related information
sho> sho> hvengel> (rendering intents, black point comp. and output channel depth). This is
sho> sho> hvengel> currently not possible.
sho> sho> hvengel>
sho> sho> hvengel> The code as it exists only does a direct conversion to XYZ in one location
sho> sho> hvengel> GfxLabColorSpace::getRGB() and then does a second conversion to an arbitrary
sho> sho> hvengel> RGB** color space in the same function. None of the other CIE based color
sho> sho> hvengel> space conversions produce an intermeadiate XYZ conversion and of course there
sho> sho> hvengel> are no generic XYZ to output color space routines.
sho> sho> hvengel>
sho> sho> hvengel> The gray and cmyk code for Lab conversions uses the getRGB() function and then
sho> sho> hvengel> does some kind of generic conversion using the RGB values. Since these RGB
sho> sho> hvengel> values are in an arbitrary RGB** color space the conversion to gray and CMYK
sho> sho> hvengel> is also arbitrary.
sho> sho> hvengel>
sho> sho> hvengel> CalGray does not do gamma compensation in getGray() as called for in the PDF
sho> sho> hvengel> spec. In addition the CalGray functions only support 8 bit depth. What
sho> sho> hvengel> happens if there is a 16bit/channel gray image in a PDF file or if a user
sho> sho> hvengel> wants 16 bit/channel output for his/her printer?
sho> sho> hvengel>
sho> sho> hvengel> CalRGB passes RGB values directly through to the output and makes no attempt
sho> sho> hvengel> to convert these into an intermeadiate XYZ color space or into the actual
sho> sho> hvengel> output colorspace. It also does not apply a gamma correction to the data as
sho> sho> hvengel> per the PDF spec.
sho> sho> hvengel>
sho> sho> hvengel> End examples:
sho> sho> hvengel>
sho> sho> hvengel> I don't think that I am pointing out anything new to most on this list. When
sho> sho> hvengel> I first started to look at the code I was hoping that it would not be too
sho> sho> hvengel> difficult to find the places where CM hooks could be put in place and that
sho> sho> hvengel> perhaps I could spend a few days putting together a set of patches that would
sho> sho> hvengel> provide a starting place. But it appears that the code needs significant
sho> sho> hvengel> restructuring in order to even start doing the actaul color management
sho> sho> hvengel> specific work. Fortunately the PDF specification has enough detail that it
sho> sho> hvengel> should be possible for the poppler team to do much of the restructuring work
sho> sho> hvengel> without too much involvement from someone with color management expertise.
sho> sho> hvengel>
sho> sho> hvengel> Mostly what is needed is:
sho> sho> hvengel>
sho> sho> hvengel> 1. An API for applications to specify the output color space, rendering
sho> sho> hvengel> intent, black point compensation and channel depth for a document. These are
sho> sho> hvengel> needed to correctly setup the XYZ to output color space transform.
sho> sho> hvengel>
sho> sho> hvengel> 2. The CIE related code (calRGB, calGray, Lab and ICCBased) needs to be
sho> sho> hvengel> restructured so that it has a clean division between producing the
sho> sho> hvengel> intermeadeate XYZ values and the code that does the XYZ to output color space
sho> sho> hvengel> conversion. See the diagram on pages 238 and 239 of the version 1.7 PDF
sho> sho> hvengel> Reference.
sho> sho> hvengel>
sho> sho> hvengel> Initially the ICCBased code could be left alone and calRGB, calGray and Lab
sho> sho> hvengel> would be setup to convert to XYZ but would still do the current simplistic
sho> sho> hvengel> conversions to the output color space (IE. these would all look some what like
sho> sho> hvengel> GfxLabColorSpace::getRGB() & friends) .
sho> sho> hvengel>
sho> sho> hvengel> Then the XYZ to output color space routines would be added and the calRGB,
sho> sho> hvengel> calGray and Lab routines would call them to handle the output conversion in a
sho> sho> hvengel> more correct way. It is at this point where the code would start making use
sho> sho> hvengel> of a CMS like LCMS as well as the API that was created in #1. This
sho> sho> hvengel> functionality is documented in the diagram on page 239 of the PDF version 1.7
sho> sho> hvengel> spec as "Conversion from CIE-based to device color space (not specified by
sho> sho> hvengel> PDF)".
sho> sho> hvengel>
sho> sho> hvengel> 3. At this point setting up the ICCBased routines to create XYZ intermeadiate
sho> sho> hvengel> results would be added. Once this is in place poppler would have a
sho> sho> hvengel> functioning color managed system for all of the CIE based color space types.
sho> sho> hvengel>
sho> sho> hvengel> I have not looked at the PDF specs for "Special color spaces" such as
sho> sho> hvengel> Separation, DeviceN, Indexed and Pattern so I do not know what implications
sho> sho> hvengel> there are for these in a color managed system. I have also not looked at
sho> sho> hvengel> transparancy issues but I didn't see much in the spec that related to ICCBased
sho> sho> hvengel> objects other than that it was nessassary to have to AtoB and BtoA tables in
sho> sho> hvengel> the profiles to support this and that all blending must be either in device
sho> sho> hvengel> space or in CIE space and that the spec advises that CIE is prefered.
sho> sho> hvengel>
sho> sho> hvengel> Many of you are probably asking "Why should we give a rats behind about this?"
sho> sho> hvengel> The reason I am looking at this is that the printing community is in the
sho> sho> hvengel> process of converting from PostScript to PDF as the standard document type for
sho> sho> hvengel> printing for *nix systems. Because of this they are in the process of writing
sho> sho> hvengel> a new pdftoraster filter for CUPS as well as putting together a PDF based
sho> sho> hvengel> "Common Printing Dialog" (this is a Google Summer of Code project). I asked
sho> sho> hvengel> on the printing email lists about color management in the new printing
sho> sho> hvengel> workflow. Specifcally did the new pdftoraster filter have CM support? I
sho> sho> hvengel> didn't get an answer and so I found the code and had a look. Guess what (most
sho> sho> hvengel> of you probably know this) it is using poppler and as a result it does not
sho> sho> hvengel> support color management.
sho> sho> hvengel>
sho> sho> hvengel> Printing is an important piece of the infastructure in general and
sho> sho> hvengel> particularly for anyone doing color critical work. It is currently badly
sho> sho> hvengel> broken with respect to color managemnt and it appears that until poppler has
sho> sho> hvengel> CM support or another similar library with CM support becomes available it
sho> sho> hvengel> will remain broken. So now you know what the story is and why this is
sho> sho> hvengel> important.
sho> sho> hvengel>
sho> sho> hvengel> I have color management expertise (I am the maintainer of LProf) and I have
sho> sho> hvengel> connections to the open source color management community where there are many
sho> sho> hvengel> others with CM expertise some of them with way more expertise than I have. As
sho> sho> hvengel> a community we have been working with the printing community, Xorg and the
sho> sho> hvengel> DE's trying to get the missing CM components in place.
sho> sho> hvengel>
sho> sho> hvengel> There has been major progress with color management on monitors and we now
sho> sho> hvengel> have calibration and profiling software for these devices as well as support
sho> sho> hvengel> in XOrg (with more on the way) and work is underway to extend this to include
sho> sho> hvengel> better user tools in KDE and GNOME. We also have good open source tools for
sho> sho> hvengel> profiling input devices like cameras and scanners and these profiles are now
sho> sho> hvengel> well supported by things like XSane, UFRAW and other software in this area.
sho> sho> hvengel>
sho> sho> hvengel> We also have high quality profiling software for output devices like printers.
sho> sho> hvengel> One of the major things that is missing is a viable color managed path for
sho> sho> hvengel> printing. That is I can create very high quality profiles for my printers but
sho> sho> hvengel> using them with the existing printing tools is at best difficult even for
sho> sho> hvengel> someone who really understands CM and nearly imposible for a normal user. If
sho> sho> hvengel> the CUPS pdftoraster filter had CM support much of the printing part of this
sho> sho> hvengel> would start falling in place and would become accessable to a much wider
sho> sho> hvengel> audiance. So from the point of view of the CM community poppler is now a very
sho> sho> hvengel> important piece of software.
sho> sho> hvengel>
sho> sho> hvengel> Hal
sho> sho> hvengel>
sho> sho> hvengel> PS For those interested this web page from the ICC has a link to a PDF file
sho> sho> hvengel> from Adobe that demonstrates CM or a lack of CM as the case may be:
sho> sho> hvengel>
sho> sho> hvengel> http://www.color.org/version4html.xalter
sho> sho> hvengel>
sho> sho> hvengel>
sho> sho> hvengel> **It looks like it might end up being sort of sRGB since it uses a matrix
sho> sho> hvengel> conversion and then a gamma conversion that is too simple to give actual sRGB
sho> sho> hvengel> results since sRGB has a compound gamma curve.
sho> sho> hvengel>
-------------- next part --------------
diff --git a/configure.ac b/configure.ac
index 5fa5832..0ee2813 100644
--- a/configure.ac
+++ b/configure.ac
@@ -425,6 +425,24 @@ AC_ARG_ENABLE(compile-warnings,
[Turn on compiler warnings.]),,
[enable_compile_warnings="yes"])
+dnl
+dnl Color Management
+dnl
+
+AC_ARG_ENABLE(cms,
+ AC_HELP_STRING([--disable-cms],
+ [Don't use color management system.]),
+ enable_cms=$enableval,
+ enable_cms="yes")
+if test x$enable_cms = xyes; then
+ AC_CHECK_LIB([lcms],cmsOpenProfileFromFile,,
+ AC_MSG_ERROR("*** lcms library not found ***"))
+ AC_CHECK_HEADERS([lcms.h],,
+ AC_MSG_ERROR("*** lcms headers not found ***"))
+ AC_DEFINE(USE_CMS, 1, [Defines if use cms])
+fi
+AM_CONDITIONAL(USE_CMS, test x$enable_cms = xyes)
+
if test "x$GCC" != xyes; then
enable_compile_warnings=no
fi
@@ -489,6 +507,7 @@ echo " use gtk-doc: $enable_gtk_doc"
echo " use libjpeg: $enable_libjpeg"
echo " use zlib: $enable_zlib"
echo " use libopenjpeg: $enable_libopenjpeg"
+echo " use cms: $enable_cms"
echo " command line utils: $enable_utils"
echo ""
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 7bb0667..5948061 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -39,6 +39,7 @@
#include "Page.h"
#include "GfxState.h"
#include "GfxFont.h"
+#include "GlobalParams.h"
//------------------------------------------------------------------------
@@ -224,6 +225,225 @@ void GfxColorSpace::getRGBLine(Guchar *in, unsigned int *out, int length) {
}
}
+#ifdef USE_CMS
+cmsHPROFILE GfxColorSpace::RGBProfile = NULL;
+cmsHPROFILE GfxColorSpace::displayProfile = NULL;
+GooString *GfxColorSpace::displayProfileName = NULL;
+unsigned int GfxColorSpace::displayPixelType = 0;
+GfxColorTransform *GfxColorSpace::XYZ2DisplayTransform = NULL;
+
+cmsHPROFILE GfxColorSpace::loadColorProfile(const char *fileName)
+{
+ cmsHPROFILE hp = NULL;
+ FILE *fp;
+
+ if (fileName[0] == '/') {
+ // full path
+ // check if open the file
+ if ((fp = fopen(fileName,"r")) != NULL) {
+ fclose(fp);
+ hp = cmsOpenProfileFromFile(fileName,"r");
+ }
+ return hp;
+ }
+ // try to load from user directory
+ GooString *path = globalParams->getBaseDir();
+ path->append(COLOR_PROFILE_DIR);
+ path->append(fileName);
+ // check if open the file
+ if ((fp = fopen(path->getCString(),"r")) != NULL) {
+ fclose(fp);
+ hp = cmsOpenProfileFromFile(path->getCString(),"r");
+ }
+ delete path;
+ if (hp == NULL) {
+ // load from global directory
+ path = new GooString(GLOBAL_COLOR_PROFILE_DIR);
+ path->append(fileName);
+ // check if open the file
+ if ((fp = fopen(path->getCString(),"r")) != NULL) {
+ fclose(fp);
+ hp = cmsOpenProfileFromFile(path->getCString(),"r");
+ }
+ delete path;
+ }
+ return hp;
+}
+
+static int CMSError(int ecode, const char *msg)
+{
+ error(-1,const_cast<char *>(msg));
+ return 1;
+}
+
+int GfxColorSpace::setupColorProfiles()
+{
+ static GBool initialized = gFalse;
+ cmsHTRANSFORM transform;
+ unsigned int nChannels;
+
+ // do only once
+ if (initialized) return 0;
+ initialized = gTrue;
+
+ // set error handlor
+ cmsSetErrorHandler(CMSError);
+
+ if (displayProfile == NULL) {
+ // load display profile if it was not already loaded.
+ if (displayProfileName == NULL) {
+ displayProfile = loadColorProfile("display.icc");
+ } else if (displayProfileName->getLength() > 0) {
+ displayProfile = loadColorProfile(displayProfileName->getCString());
+ }
+ }
+ // load RGB profile
+ RGBProfile = loadColorProfile("RGB.icc");
+ if (RGBProfile == NULL) {
+ /* use built in sRGB profile */
+ RGBProfile = cmsCreate_sRGBProfile();
+ }
+ // create transforms
+ if (displayProfile != NULL) {
+ displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile));
+ nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile));
+ // create transform from XYZ
+ cmsHPROFILE XYZProfile = cmsCreateXYZProfile();
+ if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
+ displayProfile,
+ COLORSPACE_SH(displayPixelType) |
+ CHANNELS_SH(nChannels) | BYTES_SH(0),
+ INTENT_RELATIVE_COLORIMETRIC,0)) == 0) {
+ error(-1, "Can't create Lab transform");
+ } else {
+ XYZ2DisplayTransform = new GfxColorTransform(transform);
+ }
+ cmsCloseProfile(XYZProfile);
+ }
+ return 0;
+}
+
+unsigned int GfxColorSpace::getCMSColorSpaceType(icColorSpaceSignature cs)
+{
+ switch (cs) {
+ case icSigXYZData:
+ return PT_XYZ;
+ break;
+ case icSigLabData:
+ return PT_Lab;
+ break;
+ case icSigLuvData:
+ return PT_YUV;
+ break;
+ case icSigYCbCrData:
+ return PT_YCbCr;
+ break;
+ case icSigYxyData:
+ return PT_Yxy;
+ break;
+ case icSigRgbData:
+ return PT_RGB;
+ break;
+ case icSigGrayData:
+ return PT_GRAY;
+ break;
+ case icSigHsvData:
+ return PT_HSV;
+ break;
+ case icSigHlsData:
+ return PT_HLS;
+ break;
+ case icSigCmykData:
+ return PT_CMYK;
+ break;
+ case icSigCmyData:
+ return PT_CMY;
+ break;
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSig6colorData:
+ case icSig7colorData:
+ case icSig8colorData:
+ case icSig9colorData:
+ case icSig10colorData:
+ case icSig11colorData:
+ case icSig12colorData:
+ case icSig13colorData:
+ case icSig14colorData:
+ case icSig15colorData:
+ default:
+ break;
+ }
+ return PT_RGB;
+}
+
+unsigned int GfxColorSpace::getCMSNChannels(icColorSpaceSignature cs)
+{
+ switch (cs) {
+ case icSigXYZData:
+ case icSigLuvData:
+ case icSigLabData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigRgbData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSigCmyData:
+ case icSig3colorData:
+ return 3;
+ break;
+ case icSigGrayData:
+ return 1;
+ break;
+ case icSigCmykData:
+ case icSig4colorData:
+ return 4;
+ break;
+ case icSig2colorData:
+ return 2;
+ break;
+ case icSig5colorData:
+ return 5;
+ break;
+ case icSig6colorData:
+ return 6;
+ break;
+ case icSig7colorData:
+ return 7;
+ break;
+ case icSig8colorData:
+ return 8;
+ break;
+ case icSig9colorData:
+ return 9;
+ break;
+ case icSig10colorData:
+ return 10;
+ break;
+ case icSig11colorData:
+ return 11;
+ break;
+ case icSig12colorData:
+ return 12;
+ break;
+ case icSig13colorData:
+ return 13;
+ break;
+ case icSig14colorData:
+ return 14;
+ break;
+ case icSig15colorData:
+ return 15;
+ default:
+ break;
+ }
+ return 3;
+}
+
+#endif
+
void GfxColorSpace::getGrayLine(Guchar *in, unsigned char *out, int length) {
int i, j, n;
GfxColor color;
@@ -311,6 +531,14 @@ GfxColorSpace *GfxCalGrayColorSpace::copy() {
return cs;
}
+// This is the inverse of MatrixLMN in Example 4.10 from the PostScript
+// Language Reference, Third Edition.
+static const double xyzrgb[3][3] = {
+ { 3.240449, -1.537136, -0.498531 },
+ { -0.969265, 1.876011, 0.041556 },
+ { 0.055643, -0.204026, 1.057229 }
+};
+
GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
GfxCalGrayColorSpace *cs;
Object obj1, obj2, obj3;
@@ -353,32 +581,127 @@ GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
}
obj2.free();
obj1.free();
+
+ cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
+ xyzrgb[0][1] * cs->whiteY +
+ xyzrgb[0][2] * cs->whiteZ);
+ cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
+ xyzrgb[1][1] * cs->whiteY +
+ xyzrgb[1][2] * cs->whiteZ);
+ cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
+ xyzrgb[2][1] * cs->whiteY +
+ xyzrgb[2][2] * cs->whiteZ);
+
return cs;
}
-void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
- *gray = clip01(color->c[0]);
-}
+// convert CalGray to media XYZ color space
+// (not multiply by the white point)
+void GfxCalGrayColorSpace::getXYZ(GfxColor *color,
+ double *pX, double *pY, double *pZ) {
+ double A;
-void GfxCalGrayColorSpace::getGrayLine(Guchar *in, Guchar *out, int length) {
- memcpy (out, in, length);
+ A = colToDbl(color->c[0]);
+ *pX = pow(A,gamma);
+ *pY = pow(A,gamma);
+ *pZ = pow(A,gamma);
}
-void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
- rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
+void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxRGB rgb;
+
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) {
+ double out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+ double X, Y, Z;
+
+ getXYZ(color,&X,&Y,&Z);
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ *gray = dblToCol(out[0]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ *gray = clip01((GfxColorComp)(0.299 * rgb.r +
+ 0.587 * rgb.g +
+ 0.114 * rgb.b + 0.5));
}
-void GfxCalGrayColorSpace::getRGBLine(Guchar *in, unsigned int *out,
- int length) {
- int i;
+void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double X, Y, Z;
+ double r, g, b;
- for (i = 0; i < length; i++)
- out[i] = (in[i] << 16) | (in[i] << 8) | (in[i] << 0);
+ getXYZ(color,&X,&Y,&Z);
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) {
+ double out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ rgb->r = dblToCol(out[0]);
+ rgb->g = dblToCol(out[1]);
+ rgb->b = dblToCol(out[2]);
+ return;
+ }
+#endif
+ X *= whiteX;
+ Y *= whiteY;
+ Z *= whiteZ;
+ // convert XYZ to RGB, including gamut mapping and gamma correction
+ r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
+ g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
+ b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
+ rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
+ rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
+ rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
+ rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
}
void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
- cmyk->c = cmyk->m = cmyk->y = 0;
- cmyk->k = clip01(gfxColorComp1 - color->c[0]);
+ GfxRGB rgb;
+ GfxColorComp c, m, y, k;
+
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) {
+ double in[gfxColorMaxComps];
+ double out[gfxColorMaxComps];
+ double X, Y, Z;
+
+ getXYZ(color,&X,&Y,&Z);
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ cmyk->c = dblToCol(out[0]);
+ cmyk->m = dblToCol(out[1]);
+ cmyk->y = dblToCol(out[2]);
+ cmyk->k = dblToCol(out[3]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
}
void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) {
@@ -553,47 +876,112 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
}
obj2.free();
obj1.free();
+
+ cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
+ xyzrgb[0][1] * cs->whiteY +
+ xyzrgb[0][2] * cs->whiteZ);
+ cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
+ xyzrgb[1][1] * cs->whiteY +
+ xyzrgb[1][2] * cs->whiteZ);
+ cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
+ xyzrgb[2][1] * cs->whiteY +
+ xyzrgb[2][2] * cs->whiteZ);
+
return cs;
}
-void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
- *gray = clip01((GfxColorComp)(0.299 * color->c[0] +
- 0.587 * color->c[1] +
- 0.114 * color->c[2] + 0.5));
+// convert CalRGB to XYZ color space
+void GfxCalRGBColorSpace::getXYZ(GfxColor *color,
+ double *pX, double *pY, double *pZ) {
+ double A, B, C;
+
+ A = colToDbl(color->c[0]);
+ B = colToDbl(color->c[1]);
+ C = colToDbl(color->c[2]);
+ *pX = mat[0]*pow(A,gammaR)+mat[3]*pow(B,gammaG)+mat[6]*pow(C,gammaB);
+ *pY = mat[1]*pow(A,gammaR)+mat[4]*pow(B,gammaG)+mat[7]*pow(C,gammaB);
+ *pZ = mat[2]*pow(A,gammaR)+mat[5]*pow(B,gammaG)+mat[8]*pow(C,gammaB);
}
-void GfxCalRGBColorSpace::getGrayLine(Guchar *in, Guchar *out, int length) {
- int i;
+void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxRGB rgb;
- for (i = 0; i < length; i++) {
- out[i] =
- (in[i * 3 + 0] * 19595 +
- in[i * 3 + 1] * 38469 +
- in[i * 3 + 2] * 7472) / 65536;
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) {
+ double out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+ double X, Y, Z;
+
+ getXYZ(color,&X,&Y,&Z);
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ *gray = dblToCol(out[0]);
+ return;
}
+#endif
+ getRGB(color, &rgb);
+ *gray = clip01((GfxColorComp)(0.299 * rgb.r +
+ 0.587 * rgb.g +
+ 0.114 * rgb.b + 0.5));
}
void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
- rgb->r = clip01(color->c[0]);
- rgb->g = clip01(color->c[1]);
- rgb->b = clip01(color->c[2]);
-}
-
-void GfxCalRGBColorSpace::getRGBLine(Guchar *in, unsigned int *out,
- int length) {
- Guchar *p;
- int i;
+ double X, Y, Z;
+ double r, g, b;
- for (i = 0, p = in; i < length; i++, p += 3)
- out[i] = (p[0] << 16) | (p[1] << 8) | (p[2] << 0);
+ getXYZ(color,&X,&Y,&Z);
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) {
+ double out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+
+ in[0] = clip01(X/whiteX);
+ in[1] = clip01(Y/whiteY);
+ in[2] = clip01(Z/whiteZ);
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ rgb->r = dblToCol(out[0]);
+ rgb->g = dblToCol(out[1]);
+ rgb->b = dblToCol(out[2]);
+ return;
+ }
+#endif
+ // convert XYZ to RGB, including gamut mapping and gamma correction
+ r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
+ g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
+ b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
+ rgb->r = dblToCol(pow(clip01(r), 0.5));
+ rgb->g = dblToCol(pow(clip01(g), 0.5));
+ rgb->b = dblToCol(pow(clip01(b), 0.5));
}
void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxRGB rgb;
GfxColorComp c, m, y, k;
- c = clip01(gfxColorComp1 - color->c[0]);
- m = clip01(gfxColorComp1 - color->c[1]);
- y = clip01(gfxColorComp1 - color->c[2]);
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) {
+ double in[gfxColorMaxComps];
+ double out[gfxColorMaxComps];
+ double X, Y, Z;
+
+ getXYZ(color,&X,&Y,&Z);
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ cmyk->c = dblToCol(out[0]);
+ cmyk->m = dblToCol(out[1]);
+ cmyk->y = dblToCol(out[2]);
+ cmyk->k = dblToCol(out[3]);
+ return;
+ }
+#endif
+ getRGB(color, &rgb);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
k = c;
if (m < k) {
k = m;
@@ -714,14 +1102,6 @@ void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) {
// GfxLabColorSpace
//------------------------------------------------------------------------
-// This is the inverse of MatrixLMN in Example 4.10 from the PostScript
-// Language Reference, Third Edition.
-static const double xyzrgb[3][3] = {
- { 3.240449, -1.537136, -0.498531 },
- { -0.969265, 1.876011, 0.041556 },
- { 0.055643, -0.204026, 1.057229 }
-};
-
GfxLabColorSpace::GfxLabColorSpace() {
whiteX = whiteY = whiteZ = 1;
blackX = blackY = blackZ = 0;
@@ -823,18 +1203,30 @@ GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) {
GfxRGB rgb;
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) {
+ double out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+
+ getXYZ(color, &in[0], &in[1], &in[2]);
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ *gray = dblToCol(out[0]);
+ return;
+ }
+#endif
getRGB(color, &rgb);
*gray = clip01((GfxColorComp)(0.299 * rgb.r +
0.587 * rgb.g +
0.114 * rgb.b + 0.5));
}
-void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+// convert L*a*b* to media XYZ color space
+// (not multiply by the white point)
+void GfxLabColorSpace::getXYZ(GfxColor *color,
+ double *pX, double *pY, double *pZ) {
double X, Y, Z;
double t1, t2;
- double r, g, b;
- // convert L*a*b* to CIE 1931 XYZ color space
t1 = (colToDbl(color->c[0]) + 16) / 116;
t2 = t1 + colToDbl(color->c[1]) / 500;
if (t2 >= (6.0 / 29.0)) {
@@ -842,21 +1234,45 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
} else {
X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
}
- X *= whiteX;
if (t1 >= (6.0 / 29.0)) {
Y = t1 * t1 * t1;
} else {
Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
}
- Y *= whiteY;
t2 = t1 - colToDbl(color->c[2]) / 200;
if (t2 >= (6.0 / 29.0)) {
Z = t2 * t2 * t2;
} else {
Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
}
- Z *= whiteZ;
+ *pX = X;
+ *pY = Y;
+ *pZ = Z;
+}
+void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double X, Y, Z;
+ double r, g, b;
+
+ getXYZ(color, &X, &Y, &Z);
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) {
+ double out[gfxColorMaxComps];
+ double in[gfxColorMaxComps];
+
+ in[0] = clip01(X);
+ in[1] = clip01(Y);
+ in[2] = clip01(Z);
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ rgb->r = dblToCol(out[0]);
+ rgb->g = dblToCol(out[1]);
+ rgb->b = dblToCol(out[2]);
+ return;
+ }
+#endif
+ X *= whiteX;
+ Y *= whiteY;
+ Z *= whiteZ;
// convert XYZ to RGB, including gamut mapping and gamma correction
r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
@@ -870,6 +1286,20 @@ void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
GfxRGB rgb;
GfxColorComp c, m, y, k;
+#ifdef USE_CMS
+ if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) {
+ double in[gfxColorMaxComps];
+ double out[gfxColorMaxComps];
+
+ getXYZ(color, &in[0], &in[1], &in[2]);
+ XYZ2DisplayTransform->doTransform(in,out,1);
+ cmyk->c = dblToCol(out[0]);
+ cmyk->m = dblToCol(out[1]);
+ cmyk->y = dblToCol(out[2]);
+ cmyk->k = dblToCol(out[3]);
+ return;
+ }
+#endif
getRGB(color, &rgb);
c = clip01(gfxColorComp1 - rgb.r);
m = clip01(gfxColorComp1 - rgb.g);
@@ -926,10 +1356,22 @@ GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
iccProfileStream = *iccProfileStreamA;
rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
+#ifdef USE_CMS
+ transform = NULL;
+ lineTransform = NULL;
+#endif
}
GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
delete alt;
+#ifdef USE_CMS
+ if (transform != NULL) {
+ if (transform->unref() == 0) delete transform;
+ }
+ if (lineTransform != NULL) {
+ if (lineTransform->unref() == 0) delete lineTransform;
+ }
+#endif
}
GfxColorSpace *GfxICCBasedColorSpace::copy() {
@@ -941,6 +1383,12 @@ GfxColorSpace *GfxICCBasedColorSpace::copy() {
cs->rangeMin[i] = rangeMin[i];
cs->rangeMax[i] = rangeMax[i];
}
+#ifdef USE_CMS
+ cs->transform = transform;
+ if (transform != NULL) transform->ref();
+ cs->lineTransform = lineTransform;
+ if (lineTransform != NULL) lineTransform->ref();
+#endif
return cs;
}
@@ -1015,24 +1463,163 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
}
obj2.free();
obj1.free();
+
+#ifdef USE_CMS
+ arr->get(1, &obj1);
+ dict = obj1.streamGetDict();
+ Guchar *profBuf;
+ unsigned int bufSize;
+ Stream *iccStream = obj1.getStream();
+ int c;
+ unsigned int size = 0;
+
+ bufSize = 65536;
+ profBuf = (Guchar *)gmallocn(bufSize,1);
+ iccStream->reset();
+ while ((c = iccStream->getChar()) != EOF) {
+ if (bufSize <= size) {
+ bufSize += 65536;
+ profBuf = (Guchar *)greallocn(profBuf,bufSize,1);
+ }
+ profBuf[size++] = c;
+ }
+ cmsHPROFILE hp = cmsOpenProfileFromMem(profBuf,size);
+ gfree(profBuf);
+ if (hp == 0) {
+ error(-1, "read ICCBased color space profile error");
+ } else {
+ cmsHPROFILE dhp = displayProfile;
+ if (dhp == NULL) dhp = RGBProfile;
+ unsigned int cst = getCMSColorSpaceType(cmsGetColorSpace(hp));
+ unsigned int dNChannels = getCMSNChannels(cmsGetColorSpace(dhp));
+ unsigned int dcst = getCMSColorSpaceType(cmsGetColorSpace(dhp));
+ cmsHTRANSFORM transform;
+ if ((transform = cmsCreateTransform(hp,
+ COLORSPACE_SH(cst) |CHANNELS_SH(nCompsA) | BYTES_SH(0),
+ dhp,
+ COLORSPACE_SH(dcst) |
+ CHANNELS_SH(dNChannels) | BYTES_SH(0),
+ INTENT_RELATIVE_COLORIMETRIC,0)) == 0) {
+ error(-1, "Can't create transform");
+ }
+ cs->transform = new GfxColorTransform(transform);
+ if (dcst == PT_RGB) {
+ // create line transform only when the display is RGB type color space
+ if ((transform = cmsCreateTransform(hp,
+ CHANNELS_SH(nCompsA) | BYTES_SH(1),dhp,
+ TYPE_RGB_8,INTENT_RELATIVE_COLORIMETRIC,0)) == 0) {
+ error(-1, "Can't create transform");
+ }
+ cs->lineTransform = new GfxColorTransform(transform);
+ }
+ cmsCloseProfile(hp);
+ }
+ obj1.free();
+#endif
return cs;
}
void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+#ifdef USE_CMS
+ if (transform != 0 && displayPixelType == PT_GRAY) {
+ double in[gfxColorMaxComps];
+ double out[gfxColorMaxComps];
+
+ for (int i = 0;i < nComps;i++) {
+ in[i] = colToDbl(color->c[i]);
+ }
+ transform->doTransform(in,out,1);
+ *gray = dblToCol(out[0]);
+ } else {
+ GfxRGB rgb;
+ getRGB(color,&rgb);
+ *gray = clip01((GfxColorComp)(0.3 * rgb.r +
+ 0.59 * rgb.g +
+ 0.11 * rgb.b + 0.5));
+ }
+#else
alt->getGray(color, gray);
+#endif
}
void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+#ifdef USE_CMS
+ if (transform != 0
+ && (displayProfile == NULL || displayPixelType == PT_RGB)) {
+ double in[gfxColorMaxComps];
+ double out[gfxColorMaxComps];
+
+ for (int i = 0;i < nComps;i++) {
+ in[i] = colToDbl(color->c[i]);
+ }
+ transform->doTransform(in,out,1);
+ rgb->r = dblToCol(out[0]);
+ rgb->g = dblToCol(out[1]);
+ rgb->b = dblToCol(out[2]);
+ } else {
+ alt->getRGB(color, rgb);
+ }
+#else
alt->getRGB(color, rgb);
+#endif
}
void GfxICCBasedColorSpace::getRGBLine(Guchar *in, unsigned int *out,
int length) {
+#ifdef USE_CMS
+ if (lineTransform != 0) {
+ for (int i = 0;i < length;i++) {
+ Guchar tmp[gfxColorMaxComps];
+
+ lineTransform->doTransform(in,tmp,1);
+ in += 3;
+ out[i] = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
+ }
+ } else {
+ alt->getRGBLine(in, out, length);
+ }
+#else
alt->getRGBLine(in, out, length);
+#endif
}
void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+#ifdef USE_CMS
+ if (transform != NULL && displayPixelType == PT_CMYK) {
+ double in[gfxColorMaxComps];
+ double out[gfxColorMaxComps];
+
+ for (int i = 0;i < nComps;i++) {
+ in[i] = colToDbl(color->c[i]);
+ }
+ transform->doTransform(in,out,1);
+ cmyk->c = dblToCol(out[0]);
+ cmyk->m = dblToCol(out[1]);
+ cmyk->y = dblToCol(out[2]);
+ cmyk->k = dblToCol(out[3]);
+ } else {
+ GfxRGB rgb;
+ GfxColorComp c, m, y, k;
+
+ getRGB(color,&rgb);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+ }
+#else
alt->getCMYK(color, cmyk);
+#endif
}
void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) {
@@ -3938,6 +4525,9 @@ GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
clipYMax = pageHeight;
saved = NULL;
+#ifdef USE_CMS
+ GfxColorSpace::setupColorProfiles();
+#endif
}
GfxState::~GfxState() {
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index ac20d35..1afc889 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -32,6 +32,9 @@
#include "goo/gtypes.h"
#include "Object.h"
#include "Function.h"
+#ifdef USE_CMS
+#include "lcms.h"
+#endif
class Array;
class GfxFont;
@@ -151,6 +154,37 @@ enum GfxColorSpaceMode {
csPattern
};
+#ifdef USE_CMS
+
+#define COLOR_PROFILE_DIR "/ColorProfiles/"
+#define GLOBAL_COLOR_PROFILE_DIR POPPLER_DATADIR COLOR_PROFILE_DIR
+
+// wrapper of cmsHTRANSFORM to copy
+class GfxColorTransform {
+public:
+ void doTransform(void *in, void *out, unsigned int size) {
+ cmsDoTransform(transform, in, out, size);
+ }
+ GfxColorTransform(cmsHTRANSFORM transformA) {
+ transform = transformA;
+ refCount = 1;
+ }
+ ~GfxColorTransform() {
+ cmsDeleteTransform(transform);
+ }
+ void ref() {
+ refCount++;
+ }
+ unsigned int unref() {
+ return --refCount;
+ }
+private:
+ GfxColorTransform() {}
+ cmsHTRANSFORM transform;
+ unsigned int refCount;
+};
+#endif
+
class GfxColorSpace {
public:
@@ -191,6 +225,32 @@ public:
static char *getColorSpaceModeName(int idx);
private:
+#ifdef USE_CMS
+protected:
+ static cmsHPROFILE RGBProfile;
+ static GooString *displayProfileName; // display profile file Name
+ static cmsHPROFILE displayProfile; // display profile
+ static unsigned int displayPixelType;
+ static GfxColorTransform *XYZ2DisplayTransform;
+ // convert color space signature to cmsColor type
+ static unsigned int getCMSColorSpaceType(icColorSpaceSignature cs);
+ static unsigned int getCMSNChannels(icColorSpaceSignature cs);
+ static cmsHPROFILE loadColorProfile(const char *fileName);
+public:
+ static int setupColorProfiles();
+ static void setDisplayProfile(cmsHPROFILE displayProfileA) {
+ displayProfile = displayProfileA;
+ }
+ static void setDisplayProfileName(GooString *name) {
+ displayProfileName = name->copy();
+ }
+ static cmsHPROFILE getRGBProfile() {
+ return RGBProfile;
+ }
+ static cmsHPROFILE getDisplayProfile() {
+ return displayProfile;
+ }
+#endif
};
//------------------------------------------------------------------------
@@ -235,8 +295,6 @@ public:
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
- virtual void getGrayLine(Guchar *in, Guchar *out, int length);
- virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
virtual int getNComps() { return 1; }
virtual void getDefaultColor(GfxColor *color);
@@ -255,6 +313,8 @@ private:
double whiteX, whiteY, whiteZ; // white point
double blackX, blackY, blackZ; // black point
double gamma; // gamma value
+ double kr, kg, kb; // gamut mapping mulitpliers
+ void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ);
};
//------------------------------------------------------------------------
@@ -299,8 +359,6 @@ public:
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
- virtual void getGrayLine(Guchar *in, Guchar *out, int length);
- virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
virtual int getNComps() { return 3; }
virtual void getDefaultColor(GfxColor *color);
@@ -323,6 +381,8 @@ private:
double blackX, blackY, blackZ; // black point
double gammaR, gammaG, gammaB; // gamma values
double mat[9]; // ABC -> XYZ transform matrix
+ double kr, kg, kb; // gamut mapping mulitpliers
+ void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ);
};
//------------------------------------------------------------------------
@@ -390,6 +450,7 @@ private:
double blackX, blackY, blackZ; // black point
double aMin, aMax, bMin, bMax; // range for the a and b components
double kr, kg, kb; // gamut mapping mulitpliers
+ void getXYZ(GfxColor *color, double *pX, double *pY, double *pZ);
};
//------------------------------------------------------------------------
@@ -429,6 +490,10 @@ private:
double rangeMin[4]; // min values for each component
double rangeMax[4]; // max values for each component
Ref iccProfileStream; // the ICC profile
+#ifdef USE_CMS
+ GfxColorTransform *transform;
+ GfxColorTransform *lineTransform; // color transform for line
+#endif
};
//------------------------------------------------------------------------
diff --git a/poppler/Makefile.am b/poppler/Makefile.am
index db9fd74..9d8644f 100644
--- a/poppler/Makefile.am
+++ b/poppler/Makefile.am
@@ -105,6 +105,10 @@ abiword_libs = \
endif
+if USE_CMS
+cms_libs = -llcms
+endif
+
INCLUDES = \
-I$(top_srcdir) \
-I$(top_srcdir)/goo \
@@ -126,6 +130,7 @@ CXXFLAGS+=$(PTHREAD_CFLAGS)
libpoppler_la_LIBADD = \
$(top_builddir)/goo/libgoo.la \
$(top_builddir)/fofi/libfofi.la \
+ $(cms_libs) \
$(splash_libs) \
$(libjpeg_libs) \
$(zlib_libs) \
More information about the poppler
mailing list