Monday, November 2, 2009

Auto-switching profiles for different displays

Some time ago a Jon sent me a nice postcard. It contained a link to his blog where he wrote about aut-changing the display profile when an external monitor is connected. He wrote a lot about it here. I also had this problem frequently on my Thinkpad T60, so I will probably try this out.

Short summary: The IBM presentation director can run commands on a display setup change, which could also be used to change the profile by a dedicated xcalib commandline.

Sunday, November 1, 2009

Unexpected xcalib applications #3: improving readability

I personally like command line terminals with a black background and white (or even green) text. However, this is not the most readable color combination and may stress one's eyes after long working sessions. In addition visually impaired people may also like to tweak the screen just for better readability.

There are two posts I've stumple across, which deal with readability. On the Adobe forums one suggested that Adobe Reader may need a feature to invert the page, i.e. to exchange background and foreground, here: The poster complains that reading PDFs is like having a bulb in front of you, which seems a valid point.

Another post comes from the Vinux development blog, here: Vinux is a special linux variant for visually impaired people. One issue for people with bad vision is wrong contrast. Hence, they propose using xcalib for applications like brightness and contrast control using keyboard shortcuts and in addition for an inverted copy of the primary screen on a second monitor, so that one can use the monitor that is more readable.

Unexpected xcalib applications #2: fixing brocken screens

There was one post on the Ubuntu forums that I didn't expect is a possible application for xcalib: fixing a brocken screen. You can find the original post here and the solution is here.

I didn't know that a screen can become completely inverted after it was dropped on the floor, but well, I just hope that this never happens to me. Nevertheless, the solution can either be to use compiz and invert everything or you can just use xcalib with the -invert switch. This switch I've added just for fun because I wanted to see whether it's possible to set arbitrary values in the video LUT. The interesting observation there was that X11 does not check the values, whereas on Windows the operating system does not allow you to set completely unlikely screen calibration values. Hence, this will only work on Linux:

Code:
xcalib -invert -alter

When you are going to do color-critical work (which I don't recommend with a knowingly broken screen!) and wanto to create an ICC profile, be careful: many calibration tools reset the LUT to the default values (the equivalent of xcalib -clear) - which are totally useless in this case to derive an ICC profile. Hence, better explicitly disable screen calibration in this case!

Thursday, October 29, 2009

Unexpected xcalib applications #1: preserving night vision

It's been a while since I have done work on xcalib or posted here on this blog but I have a little bit problems with jetlag currently, which provides me with a little bit of extra time. So, I've done a little google research on where xcalib is used in scenarios that haven't been envisioned when I wrote xcalib.

Application #1: Making the screen red to preserve night vision
(from here: http://ubuntuforums.org/showpost.php?p=6803029&postcount=4 - by sanskaras)

The trick is basically to switch off green and blue entirely. The proposed solution is modifying these two channels with the -green and -blue command line paramters. I've realized that these quite powerful commands are not documented in the README currently, hence here's the description:
-green GREENGAMMA GREENBRIGHTNESS GREENCONTRAST
-blue BLUEGAMMA BLUEBRIGHTNESS BLUECONTRAST
-red REDGAMMA REDBRIGHTNESS REDCONTRAST
With these switches and the -alter command it is possible to modify the existing color behavior.

Hence, the following is, according to the link, a possible setting for disabling green and blue.
Code:
xcalib -green .1 0 1 -alter
xcalib -blue .1 0 1 -alter
These are the currently lowest allowed parameters in xcalib, hence it's well possible that I remove these limits in future versions or add a parameter to disable a channel entirely.

When all is over or the screen became unreadable, you can always revert back to normal:
Code:
xcalib -clear

Tuesday, August 19, 2008

GUIs for ArgyllCMS - Part 3: Javascript GUI

On the mailing list for ArgyllCMS there was also a post by Gorazd, announcing his Javscript GUI for ArgyllCMS.

Third GUI: Javascript web interface by Gorazd.

Can be downloaded and be run from there.

http://x3.ntf.uni-lj.si/~gojc/Argyll%20CMS/

It wasn’t completely clear to me what it really does. First let’sstart with a screenshot:

As I understood it, it will create the command lines from the parameters you set in the web form. You then can paste this command line into your shell and run the Argyll binaries. This basically saves you time for looking up all the parameters, their meaning and allowed combinations. It can not run the applications for you since the browser can not execute binaries on your harddisk – otherwise this would require you to only download the Argyll binaries and then use the most current GUI.

Summary:

I’m a little puzzled what it really is good for right now but I think it is a different direction to what we know already (stand-alone applications for color profile generating). Extending this to a web-service that can create profiles from the user input can be nice for the future.

GUIs for ArgyllCMS - Part 2: dispcalGUI

In my previous post I announced that I would like to compare the different GUIs for ArgyllCMS. dispcalGUI was announced yesterday and I couldn't wait trying it out right after ArgyllCMSGUI.

Second GUI: dispcalGUI by Florian Höch

Win32 version can be download from http://hoech.net/dispcalGUI/dispcalGUI-v0.1b-win32-x86.zip . It also needs an existing unpacked Argyll for Win32.

When you start dispcalGUI, a command line-like window will appear and shortly after you have to select the directory for the Argyll binaries.

It is a simpler and more user-oriented GUI than Argyll CMS GUI. Clearly, many options are missing – but this can be ignored for the majority of users. The only thing I had to change was the display type to LCD and then I pressed “Calibrate & profile”.

Similarly to Argyll CMS GUI, dispcal (for calibration) will run and afterwards dispread (for measuring the patches). The test chart is not generated by dispcalGUI but it uses one of the files that come with the ZIP file. In my case, a test chart with 512 patches was used. This also takes some time and I had to abort the operation since another operation was in front of dispread’s measurement window. I then redid the “Profile only” with a much smaller test chart to save time. It the ran dispread followed by colprof and showed the final dialog afterwards:

As soon as I pressed OK, the dispwin binary was run to install the profile.

Summary:

I liked dispcalGUI because it’s much more intuitive than the command line binaries or Argyll CMS GUI. In addition, the automatic colorimeter detection worked like a charm. dispcalGUI comes much closer to lprof (which I haven’t tried for a while). There are no cons for me besides that it hides expert options- but do you really need them?

GUIs for ArgyllCMS - Part 1: ArgyllCMSGUI

Today I started a small experiment: let's try out the various graphical user interfaces for ArgyllCMS that were announced on the Argyll mailing list recently. In this first post ArgyllCMSGUI was analyzed from the user perspective. I tried to act like a normal user although I know the Argyll tools quite well.

First GUI: ArgyllGUI by Steven Greaves / Digifab.

http://www.digifab.com/ArgyllCMSGUI/

You must download both the ArgyllCMSGUI (as a ZIP archive for Win32) and the Argyll CMS itself (fort he normal user I recommend the precompiled executables). I’ve used the following download links:

http://www.argyllcms.com/Argyll_V1.0.2_win32_exe.zip

http://www.digifab.com/ArgyllCMSGUI/ArgyllCMSGUI108.zip

Then you have to put the unpacked ArgyllCMS files into any directory on your hard drive (e.g. C:\Program Files\Argyll_V1.0.2\ ). I then put the content of the ArgyllCMSGUI zip archive (the single file) into the bin folder of Argyll ( i.e. in my case C:\Program Files\Argyll_V1.0.2\bin\ ) and started the ArgyllCMSGui.exe. It will then ask you for the directory where you have your Argyll binaries – I have them in the same folder so I could just press OK. When I pressed Cancel, the ArgyllCMSGUI app crashed, btw.

Then you should see a screen like this:


I decided to first test the display calibration part, hence I pressed on the big icon with a display on it. Et voila:

It exposes all parameters of dispcal. The parameters are hacked into the software – so this is not guaranteed to work with any version of dispcal - but this shouldn’t be a big issue for the future. This list of parameters is probably overwhelming for all but the very experienced users – but Steve included the Argyll documentation in his app. Simply press the blue buble with the i in it and the window will expand to show the parameters and their meaning.

I’ve previously installed a software from MonacoSys (the software that came with my DTP94/Monaco Optix XR device). Since the provided driver does not work with Argyll, I had to exchange the USB driver first with the procedure as given on Graeme’s site:

http://www.argyllcms.com/doc/Installing_MSWindows.html Because if I did not, then clicking next simply resulted in the window being closed without any further feedback to the user.

After I had the right driver and changed the “Display Type” to “LCD”, clicking next resulted in a command line window with the typical dispcal „user interface“. I then simply followed the messages in this window, which was basically to self-calibrate the instrument and select the user-controls that are available for the display (brightness, contrast, gain for red, green and blue). Since my laptop display has none of these, I pressed 7 for continuing. After a while and several measured patches a file argyllcal.cal was residing in the folder of ArgyllCMSGUI.

Then a new window appeared on the screen

This window is for configuring “targen”, the Argyll application that creates the measurement patches for all devices. The “Target Colorant Type” was already set to “Video RGB”, so I pressed Next. When I did this a new patch, named argylldisplay.ti1 was created in the working directory and a new window appeared:

This window configures the dispread application. The names of the output file of the previous running applications were already inserted into the fields, beside that I had to change the display type again from CRT to LCD.


Once again you have to self-calibrate the instrument. As you see, a patch consisting of 836 patches was created by targen that is then read after any key is pressed. Before measurement starts, the calibration is applied to the display (your display’s overall color appearance may notably change).

After the vast amount of patches was read (for me it took ~2 seconds per patch, so the overall procedure took half an hour), another window of Argyll CMS GUI appeared.


In this window the profile creation parameters can be set. By default, only the most upper region is visible. I decided to only fill out the manufacturer, model and description fields so that I can distinguish the profile from other profiles I have created or will create in the future. After clinking OK, the window closed. I was wondering where the profile is expected to reside on my hard drive but couldn’t find it. However, there was a debug file created for every step of Argyll CMS GUI that contains the command line for the invoked Argyll tools. So I retyped the command in a normal CMD shell:


C:\Program Files\Argyll_V1.0.2>"C:\Program Files\Argyll_V1.0.2\bin\colprof.exe" -v -A"Lenovo" -M"Thinkpad T60 SXGA+ LCD" -D"profile created using Argyll CMS GUI

on 2008-08-19" -qm -L100 -al -iD50 -o1931_2 -tp -Ts "argylldisplay"

C:\Program Files\Argyll_V1.0.2\bin\colprof.exe: Error - Requested spectral interpretation when data not available


Basically, there was an error that the “-o” and “-i” parameter are not allowed when only colorimetric data (as is when I use a colorimeter for display profile creation) are available. So I simply removed the “-iD50 -o1931_2” from the line and I finally got my profile. Giving the default parameter on the command line should a) not be done by the GUI (since it’s the default parameter) and b) be ignored by colprof anyway. So far I have not seen a way to disable this behaviour and therefore the additional command line work-around is necessary.


Summary:

Very complex interface, which is basically a window for the command line programs existing in the Argyll CMS. By having the help included, people can look up the meaning of the parameters but many non-expert users will probably not understand the technical matters. The big plus is that all knobs available in the command line tools are available and the typical workflow (the order the command line applications have to be started) is included already. The big minus is that feedback to the user is virtually zero, hence errors are not displayed and users will not know what happened without starting a shell and typing the command line which is saved in the debug files. I personally see no benefit currently in using the tool because of the zero-user-feedback.

My first shot recommendations for improvement would be to pass error messages to the user, only show a subset of the options by default and eliminate the –i/-o bug.

Friday, February 15, 2008

Monitors with internal LUTs

Once a while there's a post on the openicc list that deals with (pretty expensive) TFT displays that have internal LUTs for color calibration. But what's behind all this and how does it help users if there are already tools that can calibrate monitors? The answer to the latter one is: you typically do not calibrate your monitor but the graphics adapter inside your PC - except you have a monitor with internal LUTs and calibration software like basiccolor display that knows how to handle these.

Before continuing here, we should talk about the displays. There are actually only a few displays that have an internal LUT - oh, wait, no: they allow setting the internal LUT - probably every display has an internal LUT. But the ones that expose them are typically high-end displays. The LUT of the monitor can then be set either via the monitor cable (VGA, DVI, whatever) or with a separate USB connection. The monitor cable solution was chosen by NEC whereas Eizo decided a USB connection would be better.

But what's the benefit of exposing the monitor's internal LUT? Well, the LUT is already used to adapt the TFT panel to a curve that is approximately what the user expects (sRGB) - therefore it's quite obvious that using only one LUT in the data flow can provide much better quality than one LUT inside the video card and another one in the monitor. Another advantage is the higher bit depth of the monitor internal LUTs - they are typically 10-12bits per channel (red, green and blue) whereas the LUT inside the video card is already limited by the 8bit nature of current operating systems and the DVI connection to the display that is also 8bits.

Still, this is just a rough overview for what I wanted to say: There's a demand for setting the monitor LUTs from operating systems for improved fidelity. This would be the much better alternative to monitor calibration loaders like xcalib and dispwin.

The first step is done already (at least for high-end NEC monitors): The protocol that NEC uses to set (and get) the LUTs of the display is DDC/CI, which is again based on the standard I2C bus protocol. A DDC/CI tool is also alread in place, ddccontrol. I hope that the folks working on this tool know that their work could be used for much more. Let's wait and see!

Saturday, November 24, 2007

xcalib and Linux screen savers - Part 2

In my recent post I recommended to use the notification methods of the screen savers for reloading the LUTs when the screen saver unblanks. I got a report that the method below does not work with the gnome screen saver - probably because of a problem in gnome screen saver.

The question is: what did gnome screen saver wrong - I don't know (I haven't tested it myself) but I guess it's a timing problem and the way gnome screen saver activates and deactivates. All the following applies only to gnome screen saver and not to e.g. xscreensaver. When the screen saver blanks it dims the screen to fade to the nice graphics that appear little later. For this fading the screen saver uses the LUTs - ouch - they were altered by xcalib for a reason before! When the user moves the mouse, the screen saver fades again to the desktop. At the same time it sends the message via D-Bus that it unblanks and xcalib can step in with the script, mentioned in the previous post. However, fading has not finished and at its end the LUTs are set to their default value.

One solution for this is to add a delay in the script of the previous post so that xcalib is started when the screen saver has finished its unblanking task.
The other solution is to apply a patch that is mentioned here which saves the LUTs inside gnome screen saver and reloads them when unblanking is finished. I hope this patch is integrated into gnome screen saver so we don't have to worry about these problems anymore.

Wednesday, October 31, 2007

xcalib and Linux screen savers

I was asked how you can start xcalib when the Linux screen saver deactivates.

Let's first talk about what the reason for this question may have been: Probably the screen saver alters the LUTs and resets them to their default value. It could also be possible that a 3D screen saver does some weird things with the LUTs. In any case, it seems like some screen savers require to load the LUTs again after the screen saver is disabled.

Unfortunately, there's no single screen saver program on Linux. There is the good old xscreensaver and the rather new gnome-screensaver. The later one supports D-Bus, so we can monitor a certain signal and issue the xcalib command when the screen saver deactivates. For the first one unfortunately no D-Bus signals exist (there's only a hack which is not integrated in the current xscreensaver).

So let's try to modify the FAQ Perl scripts of both screensavers for running xcalib when the screensaver unblanks.

xscrensaver:
#!/usr/bin/perl
my $blanked = 0;
open (IN, "xscreensaver-command -watch |");
while () {
if (m/^(BLANK|LOCK)/) {
if (!$blanked) {
$blanked = 1;
}
} elsif (m/^UNBLANK/) {
system "xcalib myprofile.icm";
$blanked = 0;
}
}

gnome-screensaver:
#!/usr/bin/perl
my $cmd = "dbus-monitor --session \"type='signal',interface='org.gnome.ScreenSaver',member='SessionIdleChanged'\"";
open (IN, "$cmd |");
while () {
if (m/^\s+boolean true/) {
} elsif (m/^\s+boolean false/) {
system "xcalib myprofile.icm";
}
}
I must admit that I haven't checked the scripts - but keep me informed if they don't work and I will modify them. As always, it should work with dispwin as well.

Sunday, October 28, 2007

Compiling ArgyllCMS on Ubuntu 7.10 Gutsy Gibbon

That's my log of what I had to do to build ArgyllCMS 0.7b7 from source on my laptop with Ubuntu 7.10.
  1. add yourself to the src group
    # sudo vim /etc/group
    change the line
    src:x:40:
    to
    src:x:40:yourusername
    note that yourusername is just a placeholder for your Ubuntu username
  2. install the jam build tool - use FTJam
    # sudo apt-get install ftjam
  3. install the X11 XVidMode development package
    # sudo apt-get install libxxf86vm-dev
  4. create a directory for Argyll in /usr/src , e.g.
    # mkdir argyllcms
    and enter it
    # cd argyllcms
  5. download latest Argyll version (use a beta version if available)
    # wget http://www.argyllcms.com/argyllV0.70Beta7_src.zip
    Always watch out on the Argyll website (http://www.argyllcms.com) what the latest version is and exchange the name in the above command
  6. unzip the downloaded file - watch out: there's no folder created and the content is extracted into your current directory!
    # unzip argyllV0.70Beta7_src.zip
  7. Run the build script
    # sh makeall.ksh
Now you should have your own Argyll binaries in the respective subfolders.

Friday, September 7, 2007

LUTs and XV

When browsing the internet I stumpled across this article. In summary, Xv does currently bypass the video card's LUTs in most cases. Tools like dispwin and xcalib have no effect.

It seems to me - after reading the entire thread - that these guys are willing to add hooks for color-management. Let's see what the result will be!

X-Rite DTP-94

Finally I got my brand-new X-Rite DTP-94. Actually it's a Monaco Optix XR - but I don't really care what software came with it since I wanted to use it to test the open-source ICC monitor profile creation programs: Argyll and Lprof.

I ordered it from the US since here in Germany these devices are really expensive. Now I paid 129$ + tax + shipping + customs + whatever = ~150€ - no more a bargain ;-(

Friday, August 31, 2007

Spyder2 device under Linux

Just wanted to mention that there's an effort going on for making the Spyder device work under Linux. This guy came already quite close and can read measurements from the device - however, the data format seems to be unclear at the moment of writing these lines. Here's the URL btw.: http://www.yan-ke.com/spyder/

Tuesday, August 28, 2007

Ideas on "remote monitor profiling"

Recently I was exchanging e-mails with some french fellows that use xcalib under Linux in a professional environment. They are using a remote monitor profiling trick.

Okay, how does it basically work:
  1. They have one Windows laptop, running a ICC profile generation software. On this laptop a VNC server is running. A colorimeter is attached.
  2. There' the Linux PC with the to-be-profiled monitor attached. It has a VNC client installed, displaying the Windows screen.
They are then running the profile generation software and get a valid profile for the Linux PC out of this process.

I'm still not completely sure whether xcalib should be involved somewhere in this process (I tend to think that the Linux PC is not calibrated when the attached display is profiled). But I have an idea:

What about intercepting the Windows calls to

BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID lpRamp );

BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID lpRamp );

Whenver one of these Win32-API calls is issued by the calibration software, something like an RPC is issued to the Linux PC which then sets the LUTs there. So what I'm trying to say is: The profiling software is running on the Windows laptop but calibrates and profiles the Linux PC and the attached monitor.

Since I'm not too familiar with RPC I would probably do it with ssh - the Windows PC has the right key to connect to all to-be-profiled Linux-PCs and calls xcalib there. Okay, xcalib can't do it currently, but that's not a big deal to extend it for a read from stdin feature.

The same with intercepting: I have never done it before. Don't know whether it's easy to do it. But as soon as time permits I will probably try it out.

Monday, August 27, 2007

mcalib

I just came across a new program called mcalib (hm, does this have to do something with xcalib?).

It is a calibration utility capable of calibrating monitors with the Pantone Huey colorimeter. This guy reverse-engineered the USB protocol of the Huey. Good job!

I must admit that I have no idea how good the Huey really is - but it's relatively cheap and I will probably go for one and extend my collection of colorimeters.

So far no real colorimetry is involved and mcalib only uses the video LUTs for making the display linear and so on ... But it's a good foundation and the code could be possibly integrated into ArgyllCMS.

Here's the link btw.: http://sourceforge.net/projects/mcalib

xcalib v0.8 release

Some french fellows mailed me that xcalib doesnt work with high-end video cards which use >8bit LUTs. Okay, I had to add interpolation.

Before this happened bleader and gl.tter sent me patches for multi-monitor support. Now ATI FGLRX users and Windows users should benefit from these patches and be able to set the LUTs per display (if the hardware supports this).

This resulted in a new xcalib version that you can download from
http://www.etg.e-technik.uni-erlangen.de/web/doe/xcalib

Monday, August 13, 2007

Mozilla adds color-management

Good news! Mozilla added color-management to Firefox 3.0a7. I instantly downloaded this version and tried it with my Win32 laptop: Hey, it works! There's a test on the ICC website ( http://www.color.org/version4html.xalter ) and Firefox passed it.

I was looking a little into the code changes and they are using LittleCMS for color-correction. So how can it be enabled?

Open about:config in Firefox 3.0a7 and set gfx.color_management.enabled to true.

Then either the monitor profile set in gfx.color_management.display_profile is used or then as a fallback the one provided by the system (already implemented?) and if even then no profile was found the sRGB profile integrated into LCMS is used.

There's a bug asscoiated with this new feature: https://bugzilla.mozilla.org/show_bug.cgi?id=16769 . There a lot of information can be found of what is working and what not - I will read it completely later ;-)

One of the problems seems to be that plugins (Flash!) are currently not aware of it and so it may be hard to get the same color in HTML and Flash.

CVSpyder.dll API description

For quite a while I own a Spyder2 colorimeter. I mainly use it for color-calibration with the provided software but was always keen on using it together with open-source software.

There is an open-source project called ColorimetreHCFR (a french home-cinema-enthusiasts TV calibration software). They are (ab)using CVSpyder.dll, a Win32-dynamic-link-library that comes with some Colorvision products. With this dll an external program can access the colorimeter and make measurements.

I digged a little deeper and found the first project doing so: S2Fly . This program just makes reads and displays the measured values on the screen. However, the author seems to be no more active.

But then few weeks ago I found ColorAxis - a small program which makes reads using this dll and is open-source. Unfortunately it's written in VisualBasic - a programming language I'm not at all familiar with. You can find it at http://coloraxis.sf.net .

Okay, I thought let's do it and re-engineer the API for using it in C/C++ programs. And here it is:

/* re-engineered header file for CVSypder.dll
* (c) 2007 Stefan Döhla, published under GPLv2
*
* API blatanly stolen from ColorAxis VB code
* see http://coloraxis.sf.net for ColorAxis details
*/

#ifndef __CV_SYPDER_H__
#define __CV_SPYDER_H__ __CV_SPYDER_H__

#define CV_STATUS_SUCCESS 0x01
#define CV_STATUS_FAILURE 0x00

#define CV_ERROR_API 0x00
#define CV_ERROR_SYSTEM 0x01

#define CV_ERROR_NOT_INITIALIZED 0x00010001
#define CV_ERROR_INVALID_PARAMETER 0x00010002
#define CV_ERROR_REFRESH_UNDETERMINED 0x00010003
#define CV_ERROR_TRANSMISSION_ERROR 0x00010004
#define CV_ERROR_XLNX_NOT_CONFIGURED 0x00010005
#define CV_ERROR_TIMEOUT 0x00010006
#define CV_LAST_FATAL_ERROR 0x0001ffff

#define CV_WARNING_ALREADY_INITIALIZED 0x00020001
#define CV_WARNING_TRIGGER_TIMEOUT 0x00020002
#define CV_WARNING_OVERALL_TIMEOUT 0x00020003
#define CV_WARNING_APPARENTLY_NOT_CRT 0x00020004
#define CV_WARNING_NO_CRT_CALIBRATION 0x00020005
#define CV_WARNING_NO_LCD_CALIBRATION 0x00020006
#define CV_WARNING_NO_TOK_CALIBRATION 0x00020007

#define CV_XILINX_CONFIGURED 0x00
#define CV_XILINX_READY_FOR_DOWNLOAD 0x01
#define CV_XILINX_UNCONFIGURED 0x02
#define CV_XILINX_QUERY_ERROR 0x03

#define CV_SCREENTYPE_CRT 0x01
#define CV_SCREENTYPE_LCD 0x02

#define CV_SERIAL_NUMBER_LEN 0x08

typedef unsigned char CV_STATUS;
typedef unsigned long CV_MESSAGE;
typedef unsigned short CV_SCREENTYPE;
typedef struct
{
unsigned short DriverVersion;
unsigned short HardwareVersion;
unsigned char SerialNumber[CV_SERIAL_NUMBER_LEN];
} CV_VendorData;

#define DLL_IMPORT __declspec(dllimport)
#define CALLING_CONVENTION _cdecl

#ifdef __cplusplus
extern "C" {
#endif

DLL_IMPORT CV_STATUS CALLING_CONVENTION CV_Startup(CV_VendorData * vendorData, unsigned int tmp, unsigned int tmp2);

DLL_IMPORT CV_STATUS CALLING_CONVENTION CV_GetRefreshRate(unsigned long * rate);

DLL_IMPORT CV_STATUS CALLING_CONVENTION CV_GetXYZ(unsigned short nFrames,
long * X,
long * Y,
long * Z);

DLL_IMPORT CV_STATUS CALLING_CONVENTION CV_GetXYZEx(unsigned short nFrames,
long * X,
long * Y,
long * Z,
unsigned char dolevel2);

DLL_IMPORT CV_MESSAGE CALLING_CONVENTION CV_GetDetailedError(unsigned char * systemError);

DLL_IMPORT CV_STATUS CALLING_CONVENTION CV_UseCalibration(CV_SCREENTYPE screenType);

DLL_IMPORT void CALLING_CONVENTION CV_Shutdown(void);

#ifdef __cplusplus
}
#endif

#endif /* __CV_SPYDER_H__ */

This header file can be used to create either a lib (you need to create stub functions and so on - all the nasty tricks) or use it as a template to DLLImport the functions from CVSpyder.dll .

I tested it with a small program (that includes Bruce Lindbloom's color conversion code at the beginning):

/* test for for CVSypder.dll-usage
* (c) 2007 Stefan Döhla, published under GPLv2
*
* XYZ->RGB conversion blatanly stolen from Bruce Lindbloom
* see http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_T.html
*/

#include "cvspyder.h"

#include
#include
#include

/* LERP(a,b,c) = linear interpolation macro, is 'a' when c == 0.0 and 'b' when c == 1.0 */
#define LERP(a,b,c) (((b) - (a)) * (c) + (a))

typedef struct UVT {
double u;
double v;
double t;
} UVT;

double rt[31] = { /* reciprocal temperature (K) */
DBL_MIN, 10.0e-6, 20.0e-6, 30.0e-6, 40.0e-6, 50.0e-6,
60.0e-6, 70.0e-6, 80.0e-6, 90.0e-6, 100.0e-6, 125.0e-6,
150.0e-6, 175.0e-6, 200.0e-6, 225.0e-6, 250.0e-6, 275.0e-6,
300.0e-6, 325.0e-6, 350.0e-6, 375.0e-6, 400.0e-6, 425.0e-6,
450.0e-6, 475.0e-6, 500.0e-6, 525.0e-6, 550.0e-6, 575.0e-6,
600.0e-6
};

UVT uvt[31] = {
{0.18006, 0.26352, -0.24341},
{0.18066, 0.26589, -0.25479},
{0.18133, 0.26846, -0.26876},
{0.18208, 0.27119, -0.28539},
{0.18293, 0.27407, -0.30470},
{0.18388, 0.27709, -0.32675},
{0.18494, 0.28021, -0.35156},
{0.18611, 0.28342, -0.37915},
{0.18740, 0.28668, -0.40955},
{0.18880, 0.28997, -0.44278},
{0.19032, 0.29326, -0.47888},
{0.19462, 0.30141, -0.58204},
{0.19962, 0.30921, -0.70471},
{0.20525, 0.31647, -0.84901},
{0.21142, 0.32312, -1.0182},
{0.21807, 0.32909, -1.2168},
{0.22511, 0.33439, -1.4512},
{0.23247, 0.33904, -1.7298},
{0.24010, 0.34308, -2.0637},
{0.24792, 0.34655, -2.4681}, /* Note: 0.24792 is a corrected value for the error found in W&S as 0.24702 */
{0.25591, 0.34951, -2.9641},
{0.26400, 0.35200, -3.5814},
{0.27218, 0.35407, -4.3633},
{0.28039, 0.35577, -5.3762},
{0.28863, 0.35714, -6.7262},
{0.29685, 0.35823, -8.5955},
{0.30505, 0.35907, -11.324},
{0.31320, 0.35968, -15.628},
{0.32129, 0.36011, -23.325},
{0.32931, 0.36038, -40.770},
{0.33724, 0.36051, -116.45}
};


int XYZtoCorColorTemp(double X, double Y, double Z, double *temp)
{
double us, vs, p, di, dm;
int i;


if ((X < 1.0e-20) && (Y < 1.0e-20) && (Z < 1.0e-20))
return(-1); /* protect against possible divide-by-zero failure */
us = (4.0 * X) / (X + 15.0 * Y + 3.0 * Z);
vs = (6.0 * Y) / (X + 15.0 * Y + 3.0 * Z);
dm = 0.0;
for (i = 0; i < 31; i++) {
di = (vs - uvt[i].v) - uvt[i].t * (us - uvt[i].u);
if ((i > 0) && (((di <>= 0.0)) || ((di >= 0.0) && (dm < 0.0))))
break; /* found lines bounding (us, vs) : i-1 and i */
dm = di;
}
if (i == 31)
return(-1); /* bad XYZ input, color temp would be less than minimum of 1666.7 degrees, or too far towards blue */
di = di / sqrt(1.0 + uvt[i ].t * uvt[i ].t);
dm = dm / sqrt(1.0 + uvt[i - 1].t * uvt[i - 1].t);
p = dm / (dm - di); /* p = interpolation parameter, 0.0 : i-1, 1.0 : i */
p = 1.0 / (LERP(rt[i - 1], rt[i], p));
*temp = p;
return(0); /* success */
}

int __cdecl main(int argc, char ** argv)
{
CV_VendorData data = {0};
CV_STATUS status = CV_STATUS_SUCCESS;
CV_MESSAGE message;
unsigned long rate = 0;
long Xlong=0, Ylong=0, Zlong=0;
double X=0.0, Y=0.0, Z=0.0;
double x=0.0, y=0.0;
double colorTemperature = 0.0;

status = CV_Startup(&data, 1, 1);
if(status != CV_STATUS_SUCCESS)
message = CV_GetDetailedError(&status);


status = CV_GetRefreshRate(&rate);
if(status != CV_STATUS_SUCCESS)
message = CV_GetDetailedError(&status);

if(message == CV_WARNING_APPARENTLY_NOT_CRT)
status = CV_UseCalibration(CV_SCREENTYPE_LCD);
else
status = CV_UseCalibration(CV_SCREENTYPE_CRT);
if(status != CV_STATUS_SUCCESS)
message = CV_GetDetailedError(&status);

status = CV_GetXYZ(300, &Xlong, &Ylong, &Zlong);
if(status != CV_STATUS_SUCCESS)
message = CV_GetDetailedError(&status);

X=(double)Xlong/1000.0;
Y=(double)Ylong/1000.0;
Z=(double)Zlong/1000.0;

x = X / (X+Y+Z);
y = Y / (X+Y+Z);

XYZtoCorColorTemp(X, Y, Z, &colorTemperature);

CV_Shutdown();
return 0;
}


As you see it's not that complicated making measurements with the CVSpyder API. It's important that one calls the functions in this order
  1. CV_Startup
  2. CV_GetRefreshRate
  3. CV_UseCalibration
  4. CV_GetXYZ
  5. CV_Shutdown
Initially I got bad reads because I haven't called CV_UseCalibration - there are weird results then!

Maybe I can manage to integrate this API into some open-source monitor calibration projects (argyll/lprof) but honestly, I'd be happier if the USB protocol can be hacked (maybe with the help of this API).

My first blog entry

Hello dear readers,

this is my first blog. I hope that I'm able to share some useful information about color-management with the internet community from time to time.