On Thursday 14 May 2009 11:22:14 am Albert Astals Cid wrote:
> A Dijous, 14 de maig de 2009, Pino Toscano va escriure:
> > Alle martedì 12 maggio 2009, Hal V. Engel ha scritto:
> > > Here it is. This patch applies and builds on git head as of this
> > > afternoon.
> >
> > Nice!
> > Just as a general comment: there are many whitespace-only changes (like a
> > tab that becomes four spaces); if you could avoid them, and produce a
> > patch in unified format (`git diff -U` should be enough), it would be
> > slightly more readable.
Thanks for the tip. I have not worked with git before this. So I am on a
learning curve.
> >
> > Now some comments about the Qt4 related parts:
> > > 1. I am not a cmake expert so I had to hack on qt4/src/CMakeLists.txt
> > > so that USE_CMS was defined for the qt4 stuff. Someone with more cmake
> > > expertise almost for sure needs to fix my hack.
> >
> > I don't like much the "have/don't-have LCMS" exposed in the public API.
Meaning poppler-qt4.h or are you saying that this should also apply to
GfxState.h?
> > Especially that including lcms.h would break all the poppler-qt4 library
> > users which don't have LCMS available.
Which is almost no one now days but it is still a valid point.
> >
> > The only solution I have in mind is the following: given the only LCMS
> > bit exposed is cmsHPROFILE, which internally is a void*, it could be
> > passed as Qt::HANDLE, like this:
> > void setColorProfile(Qt::HANDLE cmsProfile);
> > void setColorProfileName(const QString &name);
> > Qt::HANDLE colorRGBProfile() const;
> > Qt::HANDLE colorProfile() const;
> > and then doing 'cmsHPROFILE profile = (cmsHPROFILE)cmsProfile;' to cast
> > the profile back and forth. Of course the apidox for the function would
> > need to specify that the Qt::HANDLE refers to a cmsHPROFILE, and in case
> > there's no color management that those handles are NULL.
>
> If we are going to pass void * just pass void *, it's as ugly as a
> Qt::HANDLE and shows what you're doing more clearly imho.
I agree that using void* is more general and it would make it easier to
abstract the code into a general purpose library for use by all tool sets
rather than just Qt.
I am thinking of pulling the functions to get the system supplied monitor
profile(s) into a separate library. I think I can find a place to host this
code so that it is available to a wide range of projects. But it will take
some time to do that. In the mean time working out the details in the demo
viewer seems like the way to go.
>
> > Also, the function would always be compiled, and the actual
> > implementations making nothing when HAVE_LCMS is not defined. For this,
> > adding a static bool canManageColorProfiles();
> > would help users to know whether they can actually expect the function to
> > do something.
>
> Agreed.
USE_CMS or HAVE_LCMS? At some point it might be desirable to abstract the CMS
support so that other CMS's like ColorSysc (OS/X), the Windows CMS,
ArgyllCMS, AdobeAce ... can be used instead. The more general solution is to
use USE_CMS for this so as not to tie this to a specific CMS.
I now have the CMS related functions in the poppler-qt4 library and the demo
viewer setup so that LCMS specifics are not visible in the header files and
these functions will always be built. But if USE_CMS is not defined they will
simply return NULL or do nothing. I will look at doing the same type of thing
in GfxState.* but perhaps Koji should have a look at this.
I added
bool GfxColorSpace::cmsAvailable() and bool Document::cmsAvailable()
to make this test available for user apps.
On the other hand for poppler to meet the current PDF specification it really
needs to have CMS support. So in general not using a CMS should be
discouraged and in the longer term it should become a very rare situation for
users to not have a CMS installed since most users with up to date distros
will have lcms installed by default because may other apps now require it.
>
> > > 4. Someone with Windows and/or Mac expertise needs to write versions of
> > > qt4/demos/viewer.cpp cmsHPROFILE PdfViewer::getProfileAtom () for those
> > > other OS's for this to work on Windows and on the Mac. It might also
> > > be useful to move these functions to a support library so that they are
> > > available to anyone who uses the library.
>
> Yeah, but i don't really think that library belongs into the poppler scope,
> so let's just use that code until someone creates that lib :D
This is really more in the scope of OpenICC. So I will look into it.
>
> > > 5. I am not a gkt programmer so I made no attempt to update any of the
> > > gtk stuff to support CM. But the Qt4 code should provide enough clues
> > > for a gtk programmer to do the same basic stuff as I did with the Qt4
> > > support library and the demo viewer.
> >
> > Then the X11 specific code should be grouped inside #ifdef Q_WS_X11
> > blocks.
Yes I now have code blocks for X11, Windows and OS/X for this OS specific
code. Each OS does this in completely different ways with APIs that are very
different. So it is necessary to abstract this in a non-OS specific API. I
pulled most of the Windows and OS/X code I am using from stuff I had in LProf
for dealing with video gamma tables since the logic involved in getting the
handle for the specific monitor is the same as needed here. I also found the
rest of the Windows code in a note that had been sent to the lcms email list
by Marti Maria (the author of lcms). So most of the code has been tested in
other apps but I am still trying to understand some details in the OS/X API
and I have not located the documentation for this yet.
> >
> > Other notes:
> >
> > -) API: not sure whether it is necessary to expose 'int
> > setupDocumentColorProfiles()', it seems more worth just making sure it is
> > properly intialized when needed, either in the poppler core or when
> > creating a new SplashOutputDev?
>
> In my opinion it's not needed at all, should be automatic on creation and
> on calls that need to change something (like i guess
> setDocumentProfileName)
or setDocumentProfile(). And it appears that this is how it works although I
am not sure I understand why this happens.
>
> > -) API: in Document::setDocumentProfileName(), QStringToGooString()
> > creates a new GooString, which should be delete'd.
Done. But I don't think it is necessary since this is a local variable that
is created on the stack and it is gone as soon as the call returns.
>
> About naming, should setDocumentProfileName be setOutputProfileName? I mean
> should i set there the profile of my monitor (output) or of the document
> (input)
This is a good question. This is really a wrapper function for
GfxColorSpace::setOutputProfileName(). But it might make things clearer if
these methods were overloaded and my code now does this.
>
> Albert
>
> > -) Qt4 demo: you don't need to create and hold a new QDesktopWidget,
> > QApplication::desktop() will return the global one.
Done
> >
> > -) Qt4 demo: getProfileAtom() should be just colorProfile(), returning a
> > Qt::HANDLE and being always defined.
Actually a more meaningful name would be getMonitorProfile(...) since this is
actually what it does. I have changed this in my current code. Also Windows
and OS/X require additional information to get the correct screen handle so I
have set this up to allow that data to be passed in. In X11 with Qt these are
just dummy parms that don't do anything. But it will make the API the same in
every OS. I should add that the reason that these same parms are not needed
is that it can be handled via a QX11info::display() call so doing this in a
generic X11 way (IE. not using Qt calls) will likely also require the same
parms as Windows and OS/X. Qt does not have a similar API for Windows or
OS/X.
> >
> > -) Qt4 demo: the general coding style there is much like
> > http://qt.gitorious.org/qt/pages/QtCodingStyle, so please follow it,
> > whenever possible.
I had a look and my code is now in the correct style at least for the most
part.
I have created a new patch with these changes and it is attached here. The
getMonitorProfile() code for Windows and OS/X is completely untested and I
don't even know if it compiles at this point. But it is mostly correct and
there is perhaps a 50% chance that the Windows code is OK or at most only
needs minor tweaks to work.
Hal
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 1ca3289..8c74042 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -226,12 +226,21 @@ void GfxColorSpace::getRGBLine(Guchar *in, unsigned int *out, int length) {
}
}
+bool GfxColorSpace::cmsAvailable()
+{
+ #ifdef USE_CMS
+ return true;
+ #else
+ return false;
+ #endif
+}
+
#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::outputProfile = NULL;
+GooString *GfxColorSpace::outputProfileName = NULL;
+unsigned int GfxColorSpace::outputPixelType = 0;
+GfxColorTransform *GfxColorSpace::XYZ2OutputTransform = NULL;
cmsHPROFILE GfxColorSpace::loadColorProfile(const char *fileName)
{
@@ -279,45 +288,55 @@ static int CMSError(int ecode, const char *msg)
int GfxColorSpace::setupColorProfiles()
{
- static GBool initialized = gFalse;
- cmsHTRANSFORM transform;
+ // static GBool initialized = gFalse;
+ cmsHTRANSFORM transform = NULL;
unsigned int nChannels;
// do only once
- if (initialized) return 0;
- initialized = gTrue;
+ // No this should be done when ever the calling applications
+ // wants to use a different transform
+ // FIXME for some reason only the first time works.
+ // if (initialized) return 0;
+ // initialized = gTrue;
// set error handlor
cmsSetErrorHandler(CMSError);
- if (displayProfile == NULL) {
+ if (outputProfile == 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());
+ if (outputProfileName == NULL) {
+ // FIXME this does not make sense as this will
+ // not be valid for most users
+ outputProfile = loadColorProfile("display.icc");
+ } else if (outputProfileName->getLength() > 0) {
+ outputProfile = loadColorProfile(outputProfileName->getCString());
}
}
- // load RGB profile
- RGBProfile = loadColorProfile("RGB.icc");
+ // load fall back default RGB profile if not set.
+ // This will work for users who have not setup
+ // their display ICC profiles correctly
if (RGBProfile == NULL) {
/* use built in sRGB profile */
RGBProfile = cmsCreate_sRGBProfile();
}
+
// create transforms
- if (displayProfile != NULL) {
- displayPixelType = getCMSColorSpaceType(cmsGetColorSpace(displayProfile));
- nChannels = getCMSNChannels(cmsGetColorSpace(displayProfile));
+ if (outputProfile != NULL) {
+ outputPixelType = getCMSColorSpaceType(cmsGetColorSpace(outputProfile));
+ nChannels = getCMSNChannels(cmsGetColorSpace(outputProfile));
+
// create transform from XYZ
cmsHPROFILE XYZProfile = cmsCreateXYZProfile();
+
if ((transform = cmsCreateTransform(XYZProfile, TYPE_XYZ_DBL,
- displayProfile,
- COLORSPACE_SH(displayPixelType) |
+ outputProfile,
+ COLORSPACE_SH(outputPixelType) |
CHANNELS_SH(nChannels) | BYTES_SH(1),
INTENT_RELATIVE_COLORIMETRIC,0)) == 0) {
- error(-1, "Can't create Lab transform");
+ error(-1, "Can't create output transform\n");
} else {
- XYZ2DisplayTransform = new GfxColorTransform(transform);
+ delete XYZ2OutputTransform;
+ XYZ2OutputTransform = new GfxColorTransform(transform);
}
cmsCloseProfile(XYZProfile);
}
@@ -612,7 +631,7 @@ void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
GfxRGB rgb;
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_GRAY) {
Guchar out[gfxColorMaxComps];
double in[gfxColorMaxComps];
double X, Y, Z;
@@ -621,7 +640,7 @@ void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
in[0] = clip01(X);
in[1] = clip01(Y);
in[2] = clip01(Z);
- XYZ2DisplayTransform->doTransform(in,out,1);
+ XYZ2OutputTransform->doTransform(in,out,1);
*gray = byteToCol(out[0]);
return;
}
@@ -638,14 +657,14 @@ void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
getXYZ(color,&X,&Y,&Z);
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_RGB) {
Guchar out[gfxColorMaxComps];
double in[gfxColorMaxComps];
in[0] = clip01(X);
in[1] = clip01(Y);
in[2] = clip01(Z);
- XYZ2DisplayTransform->doTransform(in,out,1);
+ XYZ2OutputTransform->doTransform(in,out,1);
rgb->r = byteToCol(out[0]);
rgb->g = byteToCol(out[1]);
rgb->b = byteToCol(out[2]);
@@ -670,7 +689,7 @@ void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
GfxColorComp c, m, y, k;
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_CMYK) {
double in[gfxColorMaxComps];
Guchar out[gfxColorMaxComps];
double X, Y, Z;
@@ -680,7 +699,7 @@ void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
in[1] = clip01(Y);
in[2] = clip01(Z);
- XYZ2DisplayTransform->doTransform(in,out,1);
+ XYZ2OutputTransform->doTransform(in,out,1);
cmyk->c = byteToCol(out[0]);
cmyk->m = byteToCol(out[1]);
cmyk->y = byteToCol(out[2]);
@@ -908,7 +927,7 @@ void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
GfxRGB rgb;
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_GRAY) {
Guchar out[gfxColorMaxComps];
double in[gfxColorMaxComps];
double X, Y, Z;
@@ -917,7 +936,7 @@ void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
in[0] = clip01(X);
in[1] = clip01(Y);
in[2] = clip01(Z);
- XYZ2DisplayTransform->doTransform(in,out,1);
+ XYZ2OutputTransform->doTransform(in,out,1);
*gray = byteToCol(out[0]);
return;
}
@@ -934,14 +953,14 @@ void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
getXYZ(color,&X,&Y,&Z);
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_RGB) {
Guchar 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);
+ XYZ2OutputTransform->doTransform(in,out,1);
rgb->r = byteToCol(out[0]);
rgb->g = byteToCol(out[1]);
rgb->b = byteToCol(out[2]);
@@ -962,7 +981,7 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
GfxColorComp c, m, y, k;
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_CMYK) {
double in[gfxColorMaxComps];
Guchar out[gfxColorMaxComps];
double X, Y, Z;
@@ -971,7 +990,7 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
in[0] = clip01(X);
in[1] = clip01(Y);
in[2] = clip01(Z);
- XYZ2DisplayTransform->doTransform(in,out,1);
+ XYZ2OutputTransform->doTransform(in,out,1);
cmyk->c = byteToCol(out[0]);
cmyk->m = byteToCol(out[1]);
cmyk->y = byteToCol(out[2]);
@@ -1205,12 +1224,12 @@ void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) {
GfxRGB rgb;
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_GRAY) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_GRAY) {
Guchar out[gfxColorMaxComps];
double in[gfxColorMaxComps];
getXYZ(color, &in[0], &in[1], &in[2]);
- XYZ2DisplayTransform->doTransform(in,out,1);
+ XYZ2OutputTransform->doTransform(in,out,1);
*gray = byteToCol(out[0]);
return;
}
@@ -1257,14 +1276,14 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
getXYZ(color, &X, &Y, &Z);
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_RGB) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_RGB) {
Guchar out[gfxColorMaxComps];
double in[gfxColorMaxComps];
in[0] = clip01(X);
in[1] = clip01(Y);
in[2] = clip01(Z);
- XYZ2DisplayTransform->doTransform(in,out,1);
+ XYZ2OutputTransform->doTransform(in,out,1);
rgb->r = byteToCol(out[0]);
rgb->g = byteToCol(out[1]);
rgb->b = byteToCol(out[2]);
@@ -1288,12 +1307,12 @@ void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
GfxColorComp c, m, y, k;
#ifdef USE_CMS
- if (XYZ2DisplayTransform != NULL && displayPixelType == PT_CMYK) {
+ if (XYZ2OutputTransform != NULL && outputPixelType == PT_CMYK) {
double in[gfxColorMaxComps];
Guchar out[gfxColorMaxComps];
getXYZ(color, &in[0], &in[1], &in[2]);
- XYZ2DisplayTransform->doTransform(in,out,1);
+ XYZ2OutputTransform->doTransform(in,out,1);
cmyk->c = byteToCol(out[0]);
cmyk->m = byteToCol(out[1]);
cmyk->y = byteToCol(out[2]);
@@ -1495,7 +1514,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
if (hp == 0) {
error(-1, "read ICCBased color space profile error");
} else {
- cmsHPROFILE dhp = displayProfile;
+ cmsHPROFILE dhp = outputProfile;
if (dhp == NULL) dhp = RGBProfile;
unsigned int cst = getCMSColorSpaceType(cmsGetColorSpace(hp));
unsigned int dNChannels = getCMSNChannels(cmsGetColorSpace(dhp));
@@ -1532,7 +1551,7 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
#ifdef USE_CMS
- if (transform != 0 && displayPixelType == PT_GRAY) {
+ if (transform != 0 && outputPixelType == PT_GRAY) {
Guchar in[gfxColorMaxComps];
Guchar out[gfxColorMaxComps];
@@ -1556,7 +1575,7 @@ void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
#ifdef USE_CMS
if (transform != 0
- && (displayProfile == NULL || displayPixelType == PT_RGB)) {
+ && (outputProfile == NULL || outputPixelType == PT_RGB)) {
Guchar in[gfxColorMaxComps];
Guchar out[gfxColorMaxComps];
@@ -1596,7 +1615,7 @@ void GfxICCBasedColorSpace::getRGBLine(Guchar *in, unsigned int *out,
void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
#ifdef USE_CMS
- if (transform != NULL && displayPixelType == PT_CMYK) {
+ if (transform != NULL && outputPixelType == PT_CMYK) {
Guchar in[gfxColorMaxComps];
Guchar out[gfxColorMaxComps];
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index ad5fae6..1faa885 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -172,6 +172,7 @@ public:
}
~GfxColorTransform() {
cmsDeleteTransform(transform);
+ refCount = 0;
}
void ref() {
refCount++;
@@ -225,33 +226,38 @@ public:
// Return the name of the <idx>th color space mode.
static char *getColorSpaceModeName(int idx);
-private:
+ // So user apps can query to see if CMS support is built in
+ bool cmsAvailable();
+
#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;
+ static GooString *outputProfileName; // output device profile file Name
+ static cmsHPROFILE outputProfile; // output device profile
+ static unsigned int outputPixelType;
+ static GfxColorTransform *XYZ2OutputTransform;
// 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 setOutputProfile(cmsHPROFILE outputProfileA) {
+ if (outputProfile)
+ cmsCloseProfile(outputProfile);
+ outputProfile = outputProfileA;
}
- static void setDisplayProfileName(GooString *name) {
- displayProfileName = name->copy();
+ static void setOutputProfileName(GooString *name) {
+ outputProfileName = name->copy();
}
static cmsHPROFILE getRGBProfile() {
return RGBProfile;
}
- static cmsHPROFILE getDisplayProfile() {
- return displayProfile;
+ static cmsHPROFILE getOutputProfile() {
+ return outputProfile;
}
#endif
+
};
//------------------------------------------------------------------------
diff --git a/qt4/demos/viewer.cpp b/qt4/demos/viewer.cpp
index 61cea0a..71224c5 100644
--- a/qt4/demos/viewer.cpp
+++ b/qt4/demos/viewer.cpp
@@ -40,6 +40,35 @@
#include <QtGui/QMenuBar>
#include <QtGui/QMessageBox>
+#ifdef USE_CMS
+#include <lcms.h>
+#endif
+
+#ifdef Q_OS_WIN32
+
+#include <windows.h>
+#include <stdio.h>
+
+// end Q_OS_WIN32
+
+#elif defined Q_OS_DARWIN
+
+#include <Carbon/Carbon.h>
+#include <CoreServices/CoreServices.h>
+#include <IOKit/Graphics/IOGraphicsLib.h>
+#include <ApplicationServices/ApplicationServices.h>
+
+// end Q_OS_DARWIN
+
+#elif defined Q_WS_X11
+
+#include <QtGui/QX11Info>
+#include <X11/Xlib.h>
+#include <limits.h>
+#include <X11/Xatom.h>
+
+#endif // Q_WS_X11
+
PdfViewer::PdfViewer()
: QMainWindow(), m_currentPage(0), m_doc(0)
{
@@ -156,6 +185,7 @@ QSize PdfViewer::sizeHint() const
void PdfViewer::loadDocument(const QString &file)
{
+
Poppler::Document *newdoc = Poppler::Document::load(file);
if (!newdoc) {
QMessageBox msgbox(QMessageBox::Critical, tr("Open Error"), tr("Cannot open:\n") + file,
@@ -180,6 +210,11 @@ void PdfViewer::loadDocument(const QString &file)
m_doc = newdoc;
+ void* profile = getMonitorProfile(this -> mapToGlobal(this -> pos()).x(),
+ this -> mapToGlobal(this -> pos()).y());
+ if (profile)
+ m_doc -> setOutputProfile(profile);
+
m_doc->setRenderHint(Poppler::Document::TextAntialiasing, m_settingsTextAAAct->isChecked());
m_doc->setRenderHint(Poppler::Document::Antialiasing, m_settingsGfxAAAct->isChecked());
m_doc->setRenderBackend((Poppler::Document::RenderBackend)m_settingsRenderBackendGrp->checkedAction()->data().toInt());
@@ -209,6 +244,210 @@ void PdfViewer::closeDocument()
m_fileSaveCopyAct->setEnabled(false);
}
+#if defined (Q_OS_WIN32)
+
+#ifdef USE_CMS
+static int numMatchingDisplays;
+static RECT clipRegion;
+
+static BOOL CALLBACK MonitorEnumProc(
+HMONITOR hMonitor, // handle to display monitor
+HDC hdcMonitor, // NULL, because EnumDisplayMonitors hdc is NULL
+LPRECT displayCoordintes, // Virtual screen coordinates of this monitor
+LPARAM name // Context data used to pass back display name in our case
+)
+{
+ MONITORINFOEX pmi;
+
+ // check to see if this monitor contains the widget
+ if (displayCoordintes -> left <= clipRegion.left &&
+ displayCoordintes -> bottom >= clipRegion.top &&
+ displayCoordintes -> right >= clipRegion.left &&
+ displayCoordintes -> top <= clipRegion.top) {
+
+ // display contains the widget
+ pmi.cbSize = sizeof(MONITORINFOEX);
+ if (GetMonitorInfo(hMonitor, (MONITORINFO *)&pmi) == 0) {
+ // something is wrong and this needs to fail
+ qDebug("MonitorEnumProc - get_displays failed GetMonitorInfo");
+ return FALSE;
+ } else {// it worked we have the device we want
+ strcpy((char*) name, pmi.szDevice);
+ qDebug("Got a display name = %s", name);
+ numMatchingDisplays++;
+ return TRUE;
+ }
+ } else { // this is OK. The device is valid but not the one we want.
+ // dump some info to the console to help debug if things are not working
+ qDebug("display found but clipping rectagle is wrong");
+ qDebug("display rect = %i %i %i %i", displayCoordintes -> left,
+ displayCoordintes -> bottom,
+ displayCoordintes -> right,
+ displayCoordintes -> top);
+ qDebug("widget point = %i %i", clipRegion.left, clipRegion.bottom);
+ return TRUE;
+ }
+}
+
+HDC getDisplay()
+{
+ BOOL (WINAPI* pEnumDisplayDevices)(PVOID,DWORD,PVOID,DWORD);
+ char name[256];
+ HDC dispHand;
+
+ pEnumDisplayDevices = (BOOL (WINAPI*)(PVOID,DWORD,PVOID,DWORD)) GetProcAddress(LoadLibrary("USER32"), "EnumDisplayDevicesA");
+
+ numMatchingDisplays = 0;
+ if (EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&name) == 0) {
+ qDebug("getDisplay - EnumDisplayMonitors failed");
+ return NULL;
+ }
+
+ if ( numMatchingDisplays != 1 ) { // there is a problem we should only have one
+ qDebug("getDisplay - wrong number of displays %i", numMatchingDisplays);
+ return NULL;
+ } else {
+ if ((dispHand = CreateDC(name, name, NULL, NULL)) == NULL) {
+ qDebug("getDisplay - CreateDC failed");
+ return NULL;
+ }
+ else
+ return dispHand;
+ }
+}
+
+// FIXME the next two functions are untested
+
+LPSTR GetDefaultICMProfileName(HDC hDC)
+{
+ BOOL ok;
+ DWORD dwProfileLen;
+ char profileName[256];
+
+
+ dwProfileLen = 256;
+ szProfileName[0] = '\0';
+ SetICMMode(hDC, ICM_ON);
+ ok = GetICMProfile(hDC, (LPDWORD) &dwProfileLen, profileName);
+
+ if (!ok) {
+ qDebug("GetDefaultICMProfile: GetICMProfile returned FALSE on query, profileLen = %ld",
+ profileLen);
+ // DISPLAY_LASTERROR(GetLastError());
+ return NULL;
+ }
+
+ qDebug("Full profile name: %s", profileName);
+
+ return strdup(profileName);
+}
+
+#endif // USE_CMS
+
+void *PdfViewer::getMonitorProfile (int leftIn, int topIn)
+{
+ #ifdef USE_CMS
+ cmsHPROFILE profile = NULL;
+ clipRegion.left = left;
+ clipRegion.top = top;
+
+ LPSTR profileName = GetDefaultICMProfileName(getDisplay());
+ if (profileName != NULL) {
+ cmsHPROFILE profile
+ profile = cmsOpenProfileFromFile(profileName, "r");
+ if (profile == NULL)
+ qDebug("Error! lcms could not open profile %s", profileName);
+ else
+ qDebug("Profile %s was opened by lcms.", cmsTakeProductDesc(profile));
+ }
+ return (void*)profile;
+ #else
+ return NULL;
+ #endif // USE_CMS
+}
+
+//Q_OS_WIN32
+#elif defined (Q_OS_DARWIN)
+
+void* PdfViewer::getMonitorProfile (int leftIn, int topIn)
+{
+ #ifdef USE_CMS
+ const int maxDisplays = 64; // 64 should be enough for any system
+ CGDisplayErr displayStatus;
+ CGDisplayCount displayCount; // Total number of display IDs
+ CGDirectDisplayID displayIDs[maxDisplays]; // Array of display IDs
+ CGPoint point;
+
+ point.y = float(top);
+ point.x = float(left);
+
+ CMProfileRef *profile;
+
+ displayStatus = CGGetDisplaysWithPoint ( point, maxDisplays, displayIDs, &displayCount);
+ if (displayStatus != kCGErrorSuccess || displayCount!= 1) {
+ qDebug("CGGetDisplaysWithPoint returned error or the wrong number of displays");
+ return NULL;
+ } else {
+ // FIXME untested.
+ CMError error = CMGetProfileByAVID (displayIDs[0], profile);
+ if (error) {
+ qDebug("There was an error while getting the display profile. Code = %i", error);
+ return NULL;
+ } else
+ // FIXME not sure what a CMProfileRef actually is. Need to find docs
+ // to make sure that this is being converted into a cmsHPROFILE correctly
+ return (void*)profile;
+ }
+ #else
+ return NULL;
+ #endif // USE_CMS
+}
+
+// end Q_OS_DARWIN
+#elif defined (Q_WS_X11)
+
+void *PdfViewer::getMonitorProfile(int leftIn, int topIn)
+{
+ #ifdef USE_CMS
+ Atom ICCatom = 0;
+ Atom atomType = 0;
+ int format;
+ QString atomString;
+ unsigned long atomSize = 0;
+ unsigned long bytesAfter = 0;
+ LPVOID profileAtomBuffer;
+ cmsHPROFILE profile = NULL;
+
+ if (QApplication::desktop() -> numScreens() == 1
+ || QApplication::desktop() -> screenNumber(this) == 0) {
+ atomString = "_ICC_PROFILE";
+ } else
+ atomString = QString("_ICC_PROFILE_%1").arg(QApplication::desktop() -> screenNumber(this));
+
+ ICCatom = XInternAtom( QX11Info::display (), atomString.toLatin1(), False );
+
+ if( XGetWindowProperty ( QX11Info::display (), QX11Info::appRootWindow(-1),
+ ICCatom, 0, INT_MAX, False, XA_CARDINAL, &atomType,
+ &format, &atomSize, &bytesAfter,
+ (unsigned char **) &profileAtomBuffer) == Success) {
+
+ profile = cmsOpenProfileFromMem(profileAtomBuffer, atomSize);
+ XFree (profileAtomBuffer);
+ if (profile)
+ qDebug("Profile creation succeeded. Profile description = %s", cmsTakeProductDesc(profile));
+ else
+ qDebug("Got X11 _ICC_PROFILE atom but profile creation failed, will use sRGB");
+
+ return (void*) profile;
+ }
+
+ qDebug("Failed to get X11 _ICC_PROFILE atom, will use sRGB");
+ #endif // USE_CMS
+ return NULL;
+}
+
+#endif // Q_WS_X11
+
void PdfViewer::slotOpenFile()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open PDF Document"), QDir::homePath(), tr("PDF Documents (*.pdf)"));
diff --git a/qt4/demos/viewer.h b/qt4/demos/viewer.h
index 5e0eaaf..2f37a22 100644
--- a/qt4/demos/viewer.h
+++ b/qt4/demos/viewer.h
@@ -20,6 +20,13 @@
#define PDFVIEWER_H
#include <QtGui/QMainWindow>
+#include <QtGui/QDesktopWidget>
+
+#include "config.h"
+
+// #ifdef USE_CMS
+// #include <lcms.h>
+// #endif
class QAction;
class QActionGroup;
@@ -54,6 +61,9 @@ private Q_SLOTS:
void slotRenderBackend(QAction *act);
private:
+ // #ifdef USE_CMS
+ void *getMonitorProfile(int x, int y);
+ // #endif
void setPage(int page);
int page() const;
@@ -68,6 +78,7 @@ private:
QList<DocumentObserver *> m_observers;
Poppler::Document *m_doc;
+ QDesktopWidget* desktop;
};
#endif
diff --git a/qt4/src/CMakeLists.txt b/qt4/src/CMakeLists.txt
index b18c491..0772752 100644
--- a/qt4/src/CMakeLists.txt
+++ b/qt4/src/CMakeLists.txt
@@ -1,5 +1,9 @@
add_definitions(${QT4_DEFINITIONS})
+#if(ENABLE_LCMS)
+ set(USE_CMS ON)
+#endif(ENABLE_LCMS)
+
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${QT4_INCLUDE_DIR}
diff --git a/qt4/src/poppler-document.cc b/qt4/src/poppler-document.cc
index 2892df0..d60bf35 100644
--- a/qt4/src/poppler-document.cc
+++ b/qt4/src/poppler-document.cc
@@ -19,9 +19,10 @@
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <config.h>
+#include <GfxState.h>
#include "poppler-qt4.h"
-#include <config.h>
#include <ErrorCodes.h>
#include <GlobalParams.h>
#include <Outline.h>
@@ -36,6 +37,10 @@
#include "poppler-private.h"
+#ifdef USE_CMS
+#include <lcms.h>
+#endif
+
namespace Poppler {
int DocumentData::count = 0;
@@ -427,6 +432,56 @@ namespace Poppler {
m_doc->setPaperColor(color);
}
+
+ // int Document::setupDocumentColorProfiles()
+ // {
+ // return GfxColorSpace::setupColorProfiles();
+ // };
+
+
+ void Document::setOutputProfile(void* outputProfileA)
+ {
+ #ifdef USE_CMS
+ GfxColorSpace::setOutputProfile((cmsHPROFILE)outputProfileA);
+ #endif
+ }
+
+ void Document::setOutputProfileName(QString name)
+ {
+ #ifdef USE_CMS
+ GooString *profileName = QStringToGooString( name );
+ GfxColorSpace::setOutputProfileName(profileName);
+ delete profileName;
+ #endif
+ }
+
+ void *Document::getRGBProfile()
+ {
+ #ifdef USE_CMS
+ return (void*)GfxColorSpace::getRGBProfile();
+ #else
+ return NULL;
+ #endif
+ }
+
+ void *Document::getOutputProfile()
+ {
+ #ifdef USE_CMS
+ return (void*)GfxColorSpace::getOutputProfile() ;
+ #else
+ return NULL;
+ #endif
+ }
+
+ bool Document::cmsAvailable()
+ {
+ #ifdef USE_CMS
+ return true;
+ #else
+ return false;
+ #endif
+ }
+
QColor Document::paperColor() const
{
return m_doc->paperColor;
diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h
index 05c4c0d..fab9d36 100644
--- a/qt4/src/poppler-qt4.h
+++ b/qt4/src/poppler-qt4.h
@@ -23,6 +23,8 @@
#ifndef __POPPLER_QT_H__
#define __POPPLER_QT_H__
+#include <config.h>
+
#include "poppler-annotation.h"
#include "poppler-link.h"
#include "poppler-optcontent.h"
@@ -552,7 +554,7 @@ while (it->hasNext()) {
\since 0.6
**/
QString label() const;
-
+
private:
Q_DISABLE_COPY(Page)
@@ -649,8 +651,28 @@ while (it->hasNext()) {
Antialiasing = 0x00000001, ///< Antialiasing for graphics
TextAntialiasing = 0x00000002 ///< Antialiasing for text
};
+
Q_DECLARE_FLAGS( RenderHints, RenderHint )
+ /**
+
+ Color Management support functions.
+ These are wrapper functions for GfxState functions.
+
+ These are used to set and query the output device profile.
+ First call either setDocumentProfile() or setDocumentProfileName()
+ then call setupDocumentColorProfiles() to configure the output
+ colorspace.
+
+ */
+
+ // int setupDocumentColorProfiles();
+ void setOutputProfile(void *outputProfileA);
+ void setOutputProfileName(QString name);
+ void *getRGBProfile();
+ void *getOutputProfile();
+ bool cmsAvailable();
+
/**
Load the document from a file on disk
@@ -1097,11 +1119,11 @@ QString subject = m_doc->info("Subject");
*/
QStringList scripts() const;
- /**
+ /**
Destructor.
*/
~Document();
-
+
private:
Q_DISABLE_COPY(Document)
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler