summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2016-10-02 19:24:58 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2016-10-02 19:24:58 +0200
commit3db384424bd7398ffbb7a355cab8f15f3add009f (patch)
tree4536961c62454aca3ac87ee88229e4d20c0d44fa
parentd479dd1aab1c1cb907932c6595b0ef33523fc797 (diff)
New upstream version 1.9.1+repackupstream/1.9.1+repack
-rw-r--r--Readme.txt8
-rw-r--r--ccast/Readme.txt2
-rw-r--r--ccast/ccast.c2
-rw-r--r--ccast/ccmdns.c82
-rw-r--r--ccast/ccmes.c6
-rw-r--r--ccast/ccpacket.c6
-rw-r--r--cgats/License4.txt (renamed from cgats/License.txt)2
-rw-r--r--cgats/Readme.txt2
-rw-r--r--cgats/afiles2
-rw-r--r--cgats/cgats.c7
-rw-r--r--cgats/cgats.h6
-rw-r--r--cgats/cgatsstd.c12
-rw-r--r--cgats/pars.c6
-rw-r--r--cgats/pars.h13
-rw-r--r--cgats/parsstd.c6
-rw-r--r--doc/ArgyllCMS_arts_tag.html26
-rw-r--r--doc/ArgyllDoc.html4480
-rw-r--r--doc/CMP_Digital_Target-7.jpgbin0 -> 20514 bytes
-rw-r--r--doc/ChangesSummary.html90
-rw-r--r--doc/Environment.html258
-rw-r--r--doc/FWA.html7
-rw-r--r--doc/File_Formats.html2
-rw-r--r--doc/Installing_Linux.html63
-rw-r--r--doc/Installing_MSWindows.html24
-rw-r--r--doc/Installing_OSX.html585
-rw-r--r--doc/JETI_1501.jpgbin0 -> 25629 bytes
-rw-r--r--doc/License4.txt (renamed from icc/License.txt)2
-rw-r--r--doc/Performance.html137
-rw-r--r--doc/Scenarios.html5798
-rw-r--r--doc/XRGA.html137
-rw-r--r--doc/afiles4
-rw-r--r--doc/average.html60
-rw-r--r--doc/chartread.html63
-rw-r--r--doc/colprof.html341
-rw-r--r--doc/dispcal.html2836
-rw-r--r--doc/dispread.html1304
-rw-r--r--doc/dispwin.html914
-rw-r--r--doc/i1proDriver.html346
-rw-r--r--doc/iccgamut.html33
-rw-r--r--doc/iccgamutmapping.html242
-rw-r--r--doc/illumread.html564
-rw-r--r--doc/instruments.html4162
-rw-r--r--doc/oeminst.html47
-rw-r--r--doc/profcheck.html20
-rw-r--r--doc/spec2cie.html118
-rw-r--r--doc/spotread.html468
-rw-r--r--doc/synthcal.html214
-rw-r--r--doc/targen.html144
-rw-r--r--doc/ti3_format.html21
-rw-r--r--doc/tiffgamut.html34
-rw-r--r--doc/txt2ti3.html15
-rw-r--r--doc/xicclu.html125
-rw-r--r--gamut/gammap.c50
-rw-r--r--gamut/gammap.h2
-rw-r--r--gamut/gamut.c131
-rw-r--r--gamut/gamut.h14
-rw-r--r--gamut/maptest.c2
-rw-r--r--gamut/smthtest.c1
-rw-r--r--h/aconfig.h50
-rw-r--r--h/copyright.h7
-rw-r--r--h/counters.h12
-rw-r--r--h/llist.h12
-rw-r--r--h/sort.h14
-rw-r--r--h/xlist.h8
-rw-r--r--icc/License4.txt22
-rw-r--r--icc/Readme.txt2
-rw-r--r--icc/afiles2
-rw-r--r--icc/icc.c448
-rw-r--r--icc/icc.h132
-rw-r--r--icc/iccV42.h2
-rw-r--r--icc/iccdump.c2
-rw-r--r--icc/icclu.c2
-rw-r--r--icc/iccrw.c2
-rw-r--r--icc/iccstd.c2
-rw-r--r--icc/icctest.c2
-rw-r--r--icc/log.txt4
-rw-r--r--icc/lutest.c2
-rw-r--r--icc/mcheck.c2
-rw-r--r--icc/mkDispProf.c4
-rw-r--r--icc/sRGB.icmbin3268 -> 3268 bytes
-rw-r--r--imdi/cctiff.c1
-rw-r--r--imdi/greytiff.c1
-rw-r--r--imdi/itest.c1
-rw-r--r--link/collink.c9
-rw-r--r--log.txt159
-rw-r--r--makepackagebin.sh17
-rw-r--r--numlib/numsup.c304
-rw-r--r--numlib/numsup.h85
-rw-r--r--numlib/ui.c205
-rw-r--r--numlib/ui.h13
-rw-r--r--plot/plot.c54
-rw-r--r--plot/plot.h4
-rw-r--r--plot/vrml.c5
-rw-r--r--plot/vrml.h4
-rw-r--r--profile/applycal.c1
-rw-r--r--profile/colprof.c90
-rw-r--r--profile/colverify.c141
-rw-r--r--profile/invprofcheck.c1
-rw-r--r--profile/prof.h14
-rw-r--r--profile/profcheck.c24
-rw-r--r--profile/profin.c1
-rw-r--r--profile/profout.c298
-rw-r--r--profile/txt2ti3.c129
-rw-r--r--ref/CMP_Digital_Target-7.cht638
-rw-r--r--ref/ColorCheckerSG.ti2433
-rw-r--r--ref/afiles1
-rw-r--r--ref/linear.cal2
-rw-r--r--ref/sRGB.icmbin3268 -> 3268 bytes
-rw-r--r--ref/strange.cal2
-rw-r--r--rspl/Jamfile11
-rw-r--r--rspl/rev.c8763
-rw-r--r--rspl/rev.h222
-rw-r--r--rspl/revbench.c4
-rw-r--r--rspl/rspl.c8
-rw-r--r--rspl/rspl.h46
-rw-r--r--rspl/rspl1.c83
-rw-r--r--rspl/rspl1.h32
-rw-r--r--rspl/scat.c15
-rw-r--r--rspl/tnd.c4
-rw-r--r--scanin/CMP_Digital_Target-4.ti22
-rw-r--r--scanin/CMP_Digital_Target-7.cht638
-rw-r--r--scanin/ColorCheckerSG.ti2433
-rw-r--r--scanin/Jamfile1
-rw-r--r--scanin/afiles1
-rw-r--r--spectro/IntsLib_Readme.txt11
-rw-r--r--spectro/Jamfile2
-rw-r--r--spectro/Makefile.SA21
-rw-r--r--spectro/afiles5
-rw-r--r--spectro/average.c438
-rw-r--r--spectro/base64.c3
-rw-r--r--spectro/base64.h14
-rw-r--r--spectro/ccwin.c15
-rw-r--r--spectro/ccxxmake.c7
-rw-r--r--spectro/chartread.c326
-rw-r--r--spectro/colorhug.c15
-rw-r--r--spectro/colorhug.h8
-rw-r--r--spectro/conv.c659
-rw-r--r--spectro/conv.h76
-rw-r--r--spectro/cubecal.h1
-rw-r--r--spectro/dev.h41
-rw-r--r--spectro/dispcal.c86
-rw-r--r--spectro/dispread.c9
-rw-r--r--spectro/dispsup.c39
-rw-r--r--spectro/dispsup.h3
-rw-r--r--spectro/disptechs.c3
-rw-r--r--spectro/dispwin.c795
-rw-r--r--spectro/dispwin.h46
-rw-r--r--spectro/dtp20.c43
-rw-r--r--spectro/dtp20.h11
-rw-r--r--spectro/dtp22.c131
-rw-r--r--spectro/dtp22.h10
-rw-r--r--spectro/dtp41.c128
-rw-r--r--spectro/dtp41.h11
-rw-r--r--spectro/dtp51.c84
-rw-r--r--spectro/dtp51.h12
-rw-r--r--spectro/dtp92.c93
-rw-r--r--spectro/dtp92.h7
-rw-r--r--spectro/ex1.c20
-rw-r--r--spectro/ex1.h7
-rw-r--r--spectro/hcfr.c14
-rw-r--r--spectro/hcfr.h8
-rw-r--r--spectro/hidio.c40
-rw-r--r--spectro/hidio.h9
-rw-r--r--spectro/huey.c23
-rw-r--r--spectro/huey.h7
-rw-r--r--spectro/i1d3.c24
-rw-r--r--spectro/i1d3.h9
-rw-r--r--spectro/i1disp.c128
-rw-r--r--spectro/i1disp.h30
-rw-r--r--spectro/i1pro.c122
-rw-r--r--spectro/i1pro.h12
-rw-r--r--spectro/i1pro_imp.c332
-rw-r--r--spectro/i1pro_imp.h32
-rw-r--r--spectro/icoms.c481
-rw-r--r--spectro/icoms.h277
-rw-r--r--spectro/icoms_nt.c341
-rw-r--r--spectro/icoms_ux.c350
-rw-r--r--spectro/illumread.c68
-rw-r--r--spectro/inst.c384
-rw-r--r--spectro/inst.h150
-rw-r--r--spectro/instappsup.c20
-rw-r--r--spectro/instlib.ksh22
-rw-r--r--spectro/insttypeinst.h4
-rw-r--r--spectro/insttypes.c71
-rw-r--r--spectro/insttypes.h34
-rw-r--r--spectro/iusb.h8
-rw-r--r--spectro/kleink10.c44
-rw-r--r--spectro/kleink10.h7
-rw-r--r--spectro/linear.cal2
-rw-r--r--spectro/madvrwin.c20
-rw-r--r--spectro/munki.c80
-rw-r--r--spectro/munki_imp.c55
-rw-r--r--spectro/munki_imp.h4
-rw-r--r--spectro/oemarch.c78
-rw-r--r--spectro/oeminst.c4
-rw-r--r--spectro/pollem.c2
-rw-r--r--spectro/pollem.h2
-rw-r--r--spectro/rspec.c22
-rw-r--r--spectro/sa_conv.c865
-rw-r--r--spectro/sa_conv.h233
-rw-r--r--spectro/smcube.c49
-rw-r--r--spectro/smcube.h9
-rw-r--r--spectro/spec2cie.c220
-rw-r--r--spectro/specbos.c1000
-rw-r--r--spectro/specbos.h17
-rw-r--r--spectro/spotread.c374
-rw-r--r--spectro/spyd2.c27
-rw-r--r--spectro/spyd2.h8
-rw-r--r--spectro/ss.c163
-rw-r--r--spectro/ss.h13
-rw-r--r--spectro/ss_imp.c19
-rw-r--r--spectro/ss_imp.h10
-rw-r--r--spectro/strange.cal2
-rw-r--r--spectro/synthcal.c15
-rw-r--r--spectro/usbio.c9
-rw-r--r--spectro/usbio.h4
-rw-r--r--spectro/usbio_bsd.c8
-rw-r--r--spectro/usbio_lx.c15
-rw-r--r--spectro/usbio_nt.c4
-rw-r--r--spectro/usbio_ox.c22
-rw-r--r--spectro/webwin.c33
-rw-r--r--spectro/xdg_bds.c30
-rw-r--r--spectro/xdg_bds.h2
-rw-r--r--spectro/xrga.c224
-rw-r--r--spectro/xrga.h86
-rw-r--r--target/alphix.c16
-rw-r--r--target/alphix.h6
-rw-r--r--target/ofps.c109
-rw-r--r--target/ofps.h4
-rw-r--r--target/targen.c31
-rw-r--r--ttbd.txt9
-rw-r--r--tweak/refine.c27
-rw-r--r--usb/55-Argyll.rules43
-rw-r--r--usb/ArgyllCMS.catbin3551 -> 3551 bytes
-rw-r--r--usb/ArgyllCMS.inf458
-rw-r--r--usb/ArgyllCMS.inf.d78
-rw-r--r--usb/ArgyllCMS.inf.t224
-rw-r--r--usb/ArgyllCMS_x64.catbin3535 -> 3535 bytes
-rw-r--r--xicc/Jamfile13
-rw-r--r--xicc/cam02.c20
-rw-r--r--xicc/cam02.h8
-rw-r--r--xicc/cam02plot.c6
-rw-r--r--xicc/cam02ref.h13
-rw-r--r--xicc/cam02test.c18
-rw-r--r--xicc/ccmx.c11
-rw-r--r--xicc/ccmx.h15
-rw-r--r--xicc/ccss.c13
-rw-r--r--xicc/ccss.h16
-rw-r--r--xicc/ccttest.c11
-rw-r--r--xicc/extractttag.c1
-rw-r--r--xicc/fakeCMY.c16
-rw-r--r--xicc/fbview.c5
-rw-r--r--xicc/iccgamut.c32
-rw-r--r--xicc/mpplu.c12
-rw-r--r--xicc/revfix.c1
-rw-r--r--xicc/specplot.c154
-rw-r--r--xicc/specsubsamp.c11
-rw-r--r--xicc/spectest.c2
-rw-r--r--xicc/spectest2.c2
-rw-r--r--xicc/tiffgamut.c30
-rw-r--r--xicc/tiffgmts.c1
-rw-r--r--xicc/xcal.c46
-rw-r--r--xicc/xcal.h23
-rw-r--r--xicc/xcam.c7
-rw-r--r--xicc/xcam.h3
-rw-r--r--xicc/xcolorants.c10
-rw-r--r--xicc/xcolorants.h12
-rw-r--r--xicc/xdevlin.c2
-rw-r--r--xicc/xfbview.c177
-rw-r--r--xicc/xfit.c22
-rw-r--r--xicc/xicc.c32
-rw-r--r--xicc/xicc.h47
-rw-r--r--xicc/xicclu.c91
-rw-r--r--xicc/xlut.c669
-rw-r--r--xicc/xmatrix.c20
-rw-r--r--xicc/xmono.c4
-rw-r--r--xicc/xspect.c258
-rw-r--r--xicc/xspect.h172
-rw-r--r--yajl/yajl_common.h50
-rw-r--r--yajl/yajl_gen.c2
280 files changed, 35189 insertions, 15514 deletions
diff --git a/Readme.txt b/Readme.txt
index 1550f1b..de57d9a 100644
--- a/Readme.txt
+++ b/Readme.txt
@@ -1,8 +1,8 @@
-Argyll CMS README file - Version 1.8.2
+Argyll CMS README file - Version 1.9.0
--------------------------------------
-Date: 26th October 2015
+Date: 28th September 2016
Author: Graeme Gill
Introduction
@@ -10,7 +10,7 @@ Introduction
ArgyllCMS is an ICC compatible color management system, available
as Open Source. It supports accurate ICC profile creation for scanners,
cameras and film recorders, and calibration and profiling of displays
-and RGB & CMYK printers. Device Link can be created with a wide variety
+and RGB, CMY & CMYK printers. Device Link can be created with a wide variety
of advanced options, including specialized Video calibration standards
and 3dLuts. Spectral sample data is supported, allowing a selection of
illuminants observer types, and paper fluorescent whitener additive
@@ -26,7 +26,7 @@ provided for each major tool, and a general guide to using the tools for
typical color management tasks is also available. A mailing list provides
support for more advanced usage.
-This is Version 1.8.3, a bug fix update to V1.8.2.
+This is Version 1.9.1, a feature and bug fix update to the last major release V1.8.3.
The first public release of icclib was in November 1998,
and of Argyll was in October 2000. Code development commenced in 1995. See
Changes Summary for an overview of changes since the last release. Changes
diff --git a/ccast/Readme.txt b/ccast/Readme.txt
index 3b95267..6823ba9 100644
--- a/ccast/Readme.txt
+++ b/ccast/Readme.txt
@@ -9,4 +9,4 @@ Hierarchy:
ccpacket.c socket write/read
ccmdns.c MDNS sign on
- axTLS
+ axTLS SSL/TLS library
diff --git a/ccast/ccast.c b/ccast/ccast.c
index 981b5ae..2a2c1a8 100644
--- a/ccast/ccast.c
+++ b/ccast/ccast.c
@@ -471,7 +471,7 @@ static int start_ccast(ccast *p) {
DBG((g_log,0,"start_ccast: PING failed with '%s'\n",ccmessv_emes(merr)))
return 1;
}
-
+
/* Wait for a PONG */
// get_a_reply(p->messv, NULL);
#endif
diff --git a/ccast/ccmdns.c b/ccast/ccmdns.c
index 76ae4d1..1000db3 100644
--- a/ccast/ccmdns.c
+++ b/ccast/ccmdns.c
@@ -78,7 +78,7 @@
#include "conv.h"
#include "ccmdns.h"
-#undef DEBUG
+#undef DEBUG /* [und] */
#if defined(NT) // Windows specific
# if _WIN32_WINNT < 0x0400
@@ -128,8 +128,12 @@ typedef int SOCKET;
#ifdef DEBUG
# define DBG(xxx) a1logd xxx ;
+# define DBG2(xxx) a1logd xxx ;
+# define DLEV 0
#else
# define DBG(xxx) ;
+# define DBG2(xxx) a1logd xxx ;
+# define DLEV 2
#endif /* DEBUG */
/* ================================================================ */
@@ -285,7 +289,8 @@ static int init_send_mDNS(SOCKET *psock) {
DBG((g_log,0,"[disabling loopback failed with %d]\n",ERRNO))
}
-#ifdef NEVER // We only want this to be local
+ /* Is this desirable ? */
+
/* increase the IP TTL from the default of one to 64, so our
* multicast datagrams can get off of the local network
*/
@@ -297,7 +302,6 @@ static int init_send_mDNS(SOCKET *psock) {
closesocket(sock);
return 1;
}
-#endif
if (psock != NULL)
*psock = sock;
@@ -572,80 +576,56 @@ static int receive_mDNS(SOCKET sock, ccast_id ***ids, int emsec) {
/* Get a list of Chromecasts. Return NULL on error */
/* Last pointer in array is NULL */
-/* Takes 0.5 second to return */
+/* Takes 1.0 second to return */
ccast_id **get_ccids() {
ccast_id **ids = NULL;
- int i, j;
+ int i, j, k;
unsigned int smsec;
+ int waittime = 100;
SOCKET ssock, rsock;
+ DBG2((g_log,DLEV,"get_ccids: called\n"))
+
if (init_mDNS()) {
- DBG((g_log,0,"init_mDNS() failed\n"))
+ DBG2((g_log,0,"get_ccids: init_mDNS() failed\n"))
return NULL;
}
if (init_send_mDNS(&ssock)) {
- DBG((g_log,0,"init_send_mDNS() failed\n"))
+ DBG2((g_log,0,"get_ccids: init_send_mDNS() failed\n"))
return NULL;
}
if (init_receive_mDNS(&rsock)) {
- DBG((g_log,0,"init_receive_mDNS() failed\n"))
+ DBG2((g_log,0,"get_ccids: init_receive_mDNS() failed\n"))
closesocket(ssock);
return NULL;
}
smsec = msec_time();
- DBG((g_log,0,"Sending mDNS query:\n"))
- if (send_mDNS(ssock)) {
- DBG((g_log,0,"send_mDNS() #1 failed\n"))
- closesocket(ssock);
- closesocket(rsock);
- return NULL;
- }
-
- if (receive_mDNS(rsock, &ids, 100)) {
- DBG((g_log,0,"receive_mDNS() #1 failed\n"))
- closesocket(ssock);
- closesocket(rsock);
- return NULL;
- }
-
- if (ids == NULL && (msec_time() - smsec) < 200) {
+ /* Try a few times, with increasing response wait time */
+ for (k = 1; ids == NULL && (msec_time() - smsec) < 1000; k++) {
- DBG((g_log,0,"Sending another mDNS query:\n"))
+ DBG2((g_log,DLEV,"get_ccids: Sending mDNS query #%d:\n",k))
if (send_mDNS(ssock)) {
- DBG((g_log,0,"send_mDNS() #2 failed\n"))
- closesocket(ssock);
- closesocket(rsock);
- return NULL;
- }
-
- if (receive_mDNS(rsock, &ids, 500)) {
- DBG((g_log,0,"receive_mDNS() #2 failed\n"))
+ DBG2((g_log,0,"get_ccids: send_mDNS() #1 failed\n"))
closesocket(ssock);
closesocket(rsock);
return NULL;
}
- }
-
- if (ids == NULL) {
-
- DBG((g_log,0,"Sending a final mDNS query:\n"))
- if (send_mDNS(ssock)) {
- DBG((g_log,0,"send_mDNS() #3 failed\n"))
+
+ DBG2((g_log,DLEV,"get_ccids: Waiting for mDNS reply #%d:\n",k))
+ if (receive_mDNS(rsock, &ids, waittime)) {
+ DBG2((g_log,0,"get_ccids: receive_mDNS() #%d failed\n",k))
closesocket(ssock);
closesocket(rsock);
return NULL;
}
+ if (ids != NULL)
+ DBG2((g_log,DLEV,"get_ccids: Got reply\n"))
- if (receive_mDNS(rsock, &ids, 500)) {
- DBG((g_log,0,"receive_mDNS() #3 failed\n"))
- closesocket(ssock);
- closesocket(rsock);
- return NULL;
- }
+ waittime *= 2;
}
closesocket(ssock);
@@ -653,8 +633,9 @@ ccast_id **get_ccids() {
/* If no ChromCasts found, return an empty list */
if (ids == NULL) {
+ DBG2((g_log,DLEV,"get_ccids: no devices found\n"))
if ((ids = calloc(sizeof(ccast_id *), 1)) == NULL) {
- DBG((g_log,0,"calloc fail\n"))
+ DBG2((g_log,0,"get_ccids: calloc fail\n"))
return NULL;
}
}
@@ -670,6 +651,13 @@ ccast_id **get_ccids() {
}
}
+ for (i = 0; ids[i] != NULL; i++) {
+ DBG2((g_log,DLEV," Entry %d:\n",i))
+ DBG2((g_log,DLEV," Name: %s\n",ids[i]->name))
+ DBG2((g_log,DLEV," IP: %s\n",ids[i]->ip))
+ }
+ DBG2((g_log,DLEV,"get_ccids: Returning %d devices\n",i))
+
return ids;
}
diff --git a/ccast/ccmes.c b/ccast/ccmes.c
index d0581d9..b8f9de0 100644
--- a/ccast/ccmes.c
+++ b/ccast/ccmes.c
@@ -42,8 +42,8 @@
#include "cast_channel.pb-c.h"
#include "ccmes.h"
-#undef LOWVERBTRACE /* Low verboseness message trace */
-#undef DEBUG /* Full message trace + debug */
+#undef LOWVERBTRACE /* [und] Low verboseness message trace */
+#undef DEBUG /* [und] Full message trace + debug */
/* ------------------------------------------------------------------- */
@@ -115,7 +115,7 @@ static void mes_dump(ccmes *mes, char *pfx) {
/* Would like to pretty print the JSON data */
/* ie. convert json_reformat.c to a function */
#ifdef DEBUG
- a1logd(g_log,0," %d bytes of text data:\n",strlen(mes->data));
+ a1logd(g_log,0," %d bytes of text data:\n",strlen((char *)mes->data));
a1logd(g_log,0," '%s'\n",mes->data);
#else
yajl_val tnode, v, i;
diff --git a/ccast/ccpacket.c b/ccast/ccpacket.c
index 2efc11f..df2a0af 100644
--- a/ccast/ccpacket.c
+++ b/ccast/ccpacket.c
@@ -37,9 +37,9 @@
# include "openssl/ssl.h" /* OpenSSL header */
#endif
-#undef DEBUG
-#undef DUMPSDATA /* Send data */
-#undef DUMPRDATA /* Receive data */
+#undef DEBUG /* [und] */
+#undef DUMPSDATA /* [und] Send data */
+#undef DUMPRDATA /* [und] Receive data */
#if defined(NT) // Windows specific
# if _WIN32_WINNT < 0x0400
diff --git a/cgats/License.txt b/cgats/License4.txt
index 7655233..6db70c8 100644
--- a/cgats/License.txt
+++ b/cgats/License4.txt
@@ -1,5 +1,5 @@
*************************************************************************
-Copyright (c) 1995-2002 Graeme W. Gill
+Copyright (c) 1995-2015 Graeme W. Gill
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/cgats/Readme.txt b/cgats/Readme.txt
index 94f3e3d..89c554e 100644
--- a/cgats/Readme.txt
+++ b/cgats/Readme.txt
@@ -6,7 +6,7 @@ Package contents:
-----------------
cgatslib.zip ZIP archive of the following files
Readme.txt This file.
-License.txt Important! - Permissions for use of this package.
+License4.txt Important! - Permissions for use of this package.
cgats.c CGATS Library source code.
cgatsstd.c I/O and malloc source code.
cgats.h CGATS Library include file. Note machine dependent defines.
diff --git a/cgats/afiles b/cgats/afiles
index e185eb7..5532110 100644
--- a/cgats/afiles
+++ b/cgats/afiles
@@ -1,5 +1,5 @@
Readme.txt
-License.txt
+License4.txt
afiles
cgats.c
cgats.h
diff --git a/cgats/cgats.c b/cgats/cgats.c
index 3e6e642..3741a5d 100644
--- a/cgats/cgats.c
+++ b/cgats/cgats.c
@@ -3,7 +3,9 @@
* Committee for Graphics Arts Technologies Standards
* CGATS.5 and IT8.7 family file I/O class
* Version 2.05
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 20/12/95
*
@@ -11,9 +13,10 @@
* All rights reserved.
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
+
/*
Should add a function to promote a field type, ie.
diff --git a/cgats/cgats.h b/cgats/cgats.h
index bc0cdd7..bf5c94e 100644
--- a/cgats/cgats.h
+++ b/cgats/cgats.h
@@ -4,7 +4,9 @@
* Committee for Graphics Arts Technologies Standards
* CGATS.5 and IT8.7 family file I/O class
* Version 2.05
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 20/12/95
*
@@ -12,7 +14,7 @@
* All rights reserved.
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/* Version of cgatslib release */
diff --git a/cgats/cgatsstd.c b/cgats/cgatsstd.c
index d8fbb34..22c17ed 100644
--- a/cgats/cgatsstd.c
+++ b/cgats/cgatsstd.c
@@ -3,6 +3,11 @@
* cgats library stdio and malloc utility classes.
* Version 2.05
*
+ * These are kept in a separate file to allow them to be
+ * selectively ommitted from the cgats library.
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 2002/10/24
*
@@ -10,13 +15,12 @@
* All rights reserved.
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
- *
- * These are kept in a separate file to allow them to be
- * selectively ommitted from the cgats library.
+ * see the License4.txt file in this directory for licensing details.
*
*/
+
+
#ifndef COMBINED_STD
#include <stdio.h>
diff --git a/cgats/pars.c b/cgats/pars.c
index 8a4e4b9..c3038d5 100644
--- a/cgats/pars.c
+++ b/cgats/pars.c
@@ -2,6 +2,9 @@
/*
* Simple ASCII file parsing object.
* Used as a base for the CGATS.5 and IT8.7 family file I/O class
+ */
+
+/*
* Version 2.05
*
* Author: Graeme W. Gill
@@ -11,9 +14,10 @@
* All rights reserved.
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
+
#define _PARS_C_ /* Turn on implimentation code */
#include <stdio.h>
diff --git a/cgats/pars.h b/cgats/pars.h
index 83bbdad..083a745 100644
--- a/cgats/pars.h
+++ b/cgats/pars.h
@@ -2,6 +2,9 @@
/*
* Simple ASCII file parsing object.
* Used as a base for the CGATS.5 and IT8.7 family file I/O class
+ */
+
+/*
* Version 2.01
*
* Author: Graeme W. Gill
@@ -11,9 +14,13 @@
* All rights reserved.
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
#undef CGATS_DEBUG_MALLOC /* Turns on partial support for filename and linenumber capture */
/* - - - - - - - - - - - - - - - - - - - - - */
@@ -237,6 +244,10 @@ extern parse *new_parse_al(cgatsAlloc *al, cgatsFile *fp); /* With allocator cla
/* Available when SEPARATE_STD is not defined: */
extern parse *new_parse(cgatsFile *fp); /* Default allocator */
+#ifdef __cplusplus
+ }
+#endif
+
#define PARS_H
#endif /* PARS_H */
diff --git a/cgats/parsstd.c b/cgats/parsstd.c
index 4443e0a..2246c97 100644
--- a/cgats/parsstd.c
+++ b/cgats/parsstd.c
@@ -1,6 +1,9 @@
/*
* parse library stdio and malloc utility classes.
+ */
+
+/*
* Version 2.05
*
* Author: Graeme W. Gill
@@ -10,13 +13,14 @@
* All rights reserved.
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*
* These are kept in a separate file to allow them to be
* selectively ommitted from the cgats library.
*
*/
+
#define _PARSSTD_C_
#ifndef COMBINED_STD
diff --git a/doc/ArgyllCMS_arts_tag.html b/doc/ArgyllCMS_arts_tag.html
index 826aa30..8b9c445 100644
--- a/doc/ArgyllCMS_arts_tag.html
+++ b/doc/ArgyllCMS_arts_tag.html
@@ -53,10 +53,10 @@
</ol>
The ICC standard "Wrong Von Kries" chromatic transform for media
white to/from PCS D50 has disadvantages in regard to color behavior
- for Output (i.e. print) profiles as well as Display profiles though.
- With most normal, white media this is not of great significance,
- since the white point shift is small, but it grows in significance
- as the color of the paper differs from white (i.e. tinted papers).<br>
+ for Output (i.e. print) profiles as well as Display profiles. With
+ most normal, white media this is not of great significance, since
+ the white point shift is small, but it grows in significance as the
+ color of the paper differs from white (i.e. tinted papers).<br>
<br>
For all these reasons, and in the pursuit of the best possible color
quality, ArgyllCMS uses the more color accurate Bradford chromatic
@@ -70,17 +70,17 @@
noticeable with tinted stock, while having minimum incompatibility
with Output profiles created for normal, white printed media by
other profiling programs because the white point shift is typically
- small. But to enable perfect compatibility of ArgyllCMS Output (i.e.
+ small (But to enable perfect compatibility of ArgyllCMS Output (i.e.
print)&nbsp; profiles with other CMM's, the default behavior can be
changed by using the <a
href="Environment.html#ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP">ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP</a>
- environment variable.<br>
+ environment variable).<br>
<br>
So the problem is that it is impossible to know for sure whether an
- ArgyllCMS create profile, ICC V2 Display profile, or other ICC
- profiles has used a Bradford or "Wrong Von Kries" chromatic
- transform in computing Absolute to/from Relative white point
- transform.<br>
+ ArgyllCMS create profile, ICC V2 Display profile, or other widely
+ used ICC profiles such as sRGB or AdobeRGB has used a Bradford or
+ "Wrong Von Kries" chromatic transform in computing Absolute to/from
+ Relative white point transform.<br>
<h2>The solution</h2>
The ArgyllCMS SigAbsToRelTransSpace 'arts' tag holds a 3x3 matrix in
the first 9 elements<sup>*</sup> of a SigS15Fixed16ArrayType in the
@@ -105,7 +105,7 @@ href="Environment.html#ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP">ARGYLL
&nbsp;&nbsp;&nbsp; 7:&nbsp; -0.06849670<br>
&nbsp;&nbsp;&nbsp; 8:&nbsp; 1.02960205<br>
</blockquote>
- In contrast, ICC standard behavior is the equivalent of a unit
+ In contrast, ICC standard behavior is the equivalent of a unity
matrix.<br>
<br>
[ Note that ArgyllCMS will write an 'arts' tag containing a Bradford
@@ -142,7 +142,9 @@ href="Environment.html#ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP">ARGYLL
the elimination of all ambiguity when the 'arts' tag is present,
allowing CMM and profile creators to use the preferred Bradford (or
other Sharpened Cone) space for Von Kries chromatic adaptation of
- the media white point to/from PCS D50.<br>
+ the media white point to/from PCS D50, and provide perfect
+ compatibility for the widely used sRGB and AdobeRGB profiles and
+ similiar.<br>
<h2>Conclusion</h2>
The 'arts' tag allows unambiguous use of the recommended Bradford
cone space transform in computing the Absolute Colorimetric (Media
diff --git a/doc/ArgyllDoc.html b/doc/ArgyllDoc.html
index a2b2ed5..e1625f4 100644
--- a/doc/ArgyllDoc.html
+++ b/doc/ArgyllDoc.html
@@ -1,63 +1,65 @@
-<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- <meta name="description" content="Root of Argyll CMS documentation">
- <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
- [Netscape]">
- <title>Argyll Documentation Top</title>
- </head>
- <body>
- <h1> Argyll CMS documentation index (V1.8.3)<br>
- </h1>
- Date:&nbsp;&nbsp; 26th October 2015<br>
- Author: Graeme Gill
- <h2><u><a name="Intro"></a>Introduction</u></h2>
- ArgyllCMS is an ICC compatible color management system, available as
- Open Source. It supports accurate ICC profile creation for scanners,
- cameras and film recorders, and calibration and profiling of
- displays and RGB &amp; CMYK printers. Device Link can be created
- with a wide variety of advanced options, including specialized Video
- calibration standards&nbsp; and 3dLuts. Spectral sample data is
- supported, allowing a selection of illuminants observer types, and
- paper fluorescent whitener additive compensation. Profiles can also
- incorporate source specific gamut mappings for perceptual and
- saturation intents. Gamut mapping and profile linking uses the
- CIECAM02 appearance model, a unique gamut mapping algorithm, and a
- wide selection of rendering intents. It also includes code for the
- fastest portable 8 bit raster color conversion engine available
- anywhere, as well as support for fast, fully accurate 16 bit
- conversion. Device color gamuts can also be viewed and compared with
- a modern Web browser using X3DOM . Comprehensive documentation is
- provided for each major tool, and a general guide to using the tools
- for typical color management tasks is also available. A mailing list
- provides support for more advanced usage.<br>
- <p>This is Version 1.8.3, a bug fix update to V1.8.2. The first
- public release of icclib was in November 1998, and of Argyll was
- in October 2000. Code development commenced in 1995. See <a
- href="ChangesSummary.html">Changes Summary</a> for an overview
- of changes since the last release. Changes between revisions is
- detailed in the <b>log.txt</b> file that accompanies the source
- code. </p>
- <p>The latest source code is available from <a
- href="http://www.argyllcms.com/">here</a>.<br>
- </p>
- <p><font color="#cc0000"><span style="font-weight: bold;">Please
- note that instruments are being driven by ArgyllCMS drivers,
- and that any problems or queries regarding instrument<br>
- operation </span><span style="font-weight: bold;">should
- first be directed to the Argyll's author(s) or the Argyll
- mailing list, and not to any</span> <span style="font-weight:
- bold;">other party.</span></font> </p>
- <p> </p>
- <h2><a href="ColorManagement.html">An Introduction to Color
- Management</a></h2>
- <p>A great introduction for non technical people is Steve Upton's <a
- href="http://www.colorwiki.com/wiki/The_Color_of_Toast">The
- Color of Toast</a>.<br>
- </p>
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ <meta name="description" content="Root of Argyll CMS documentation">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Documentation Top</title>
+ </head>
+ <body>
+ <h1> ArgyllCMS documentation index (V1.9.1)<br>
+ </h1>
+ Date:&nbsp;&nbsp; 28th September 2016<br>
+ Author: Graeme Gill
+ <h2><u><a name="Intro"></a>Introduction</u></h2>
+ ArgyllCMS is an ICC compatible color management system, available as
+ Open Source. It supports accurate ICC profile creation for scanners,
+ cameras and film recorders, and calibration and profiling of
+ displays and RGB, CMY &amp; CMYK printers. Device Link can be
+ created with a wide variety of advanced options, including
+ specialized Video calibration standards&nbsp; and 3dLuts. Spectral
+ sample data is supported, allowing a selection of illuminants
+ observer types, and paper fluorescent whitener additive
+ compensation. Profiles can also incorporate source specific gamut
+ mappings for perceptual and saturation intents. Gamut mapping and
+ profile linking uses the CIECAM02 appearance model, a unique gamut
+ mapping algorithm, and a wide selection of rendering intents. It
+ also includes code for the fastest portable 8 bit raster color
+ conversion engine available anywhere, as well as support for fast,
+ fully accurate 16 bit conversion. Device color gamuts can also be
+ viewed and compared with a modern Web browser using X3DOM .
+ Comprehensive documentation is provided for each major tool, and a
+ general guide to using the tools for typical color management tasks
+ is also available. A mailing list provides support for more advanced
+ usage.<br>
+ <p>This is Version 1.9.1, a feature and bug fix update to the last
+ major releaseV1.8.3. The first public release of icclib was in
+ November 1998, and of ArgyllCMS was in October 2000. Code
+ development commenced in 1995. See <a href="ChangesSummary.html">Changes
+
+ Summary</a> for an overview of changes since the last release.
+ Changes between revisions is detailed in the <b>log.txt</b> file
+ that accompanies the source code. </p>
+ <p>The latest source code is available from <a
+ href="http://www.argyllcms.com/">here</a>.<br>
+ </p>
+ <p><font color="#cc0000"><span style="font-weight: bold;">Please
+ note that instruments are being driven by ArgyllCMS drivers,
+ and that any problems or queries regarding instrument<br>
+ operation </span><span style="font-weight: bold;">should
+ first be directed to the Argyll's author(s) or the Argyll
+ mailing list, and not to any</span> <span style="font-weight:
+ bold;">other party.</span></font> </p>
+ <p> </p>
+ <h2><a href="ColorManagement.html">An Introduction to Color
+ Management</a></h2>
+ <p>A great introduction for non technical people is Steve Upton's <a
+ href="http://www.colorwiki.com/wiki/The_Color_of_Toast">The
+ Color of Toast</a>.<br>
+ </p>
I present here a more technical but <a href="ColorManagement.html">concise
@@ -109,51 +111,70 @@
- discussion</a> of what color management is, and why we need it,
- together with a brief overview of the ICC profile format.<br>
- <br>
- <h2 style="text-decoration: underline;">Operating Environments</h2>
- <h2> </h2>
- <p>Argyll is known to compile and run in at least the following
- environments: </p>
- 1) MSWindows XP system using Microsoft VC++ 6.0 compiler<br>
- 2) MSWindows XP system using Microsoft VC++ 8.0 Express compiler +
- Platform SDK Feb. 2003<br>
- 3) MSWindows XP system using Microsoft VC++ 9.0 Express compiler +
- Platform SDK Feb. 2003<br>
- 4) MSWindows XP system using Microsoft VC++ 10.0 Express compiler +
- Platform SDK Feb. 2003<br>
- 5) MSWindows XP system using Microsoft VC++ 11.0 Express compiler<br>
- 6) MSWindows XP system using the MingW port of the GCC compiler<br>
- 7) Linux on Fedora Core 8, 32 bit using gcc <br>
- 8) Linux on Fedora Core 8, 64 bit using gcc<br>
- 9) Apple OS X 10.3 PPC using GCC<br>
- 10) Apple OS X 10.4, 10.5, 10.6 Intel using GCC<br>
- 11) Apple OS X10.7 Intel using&nbsp; Clang<br>
- <br>
- Additionally it is also known to run on:<br>
- <br>
- &nbsp;MSWindows 2000, Vista &amp; Windows 7 32 bit.<br>
- &nbsp;MSWindows Vista 64bit, Windows 7, 8, 8.1 64 bit.<br>
- &nbsp;Linux Ubuntu 7.10<br>
- &nbsp;Linux Kubuntu 7.10<br>
- &nbsp;Linux Mandriva 2008.0<br>
- &nbsp;Linux OpenSuSE 10.3<br>
- &nbsp;Linux Whitebox 4.2/2<br>
- <p>but may well compile and run correctly in many more than this,
- including OS X 10.8, 10.9 and 10.10 &amp; MSWin 10. </p>
- This is a <span style="font-weight: bold;">command line terminal</span>
- only environment. Those unfamiliar with command line environments
- should consult an appropriate tutorial for their environment if they
- are interested in using this software. See the listing of <a
- href="#cltutes">tutorials</a> below.<span style="font-weight:
- bold;"></span><br>
- <br>
- The following color measuring instruments are directly supported:<br>
- <br>
- JETI:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#specbos">specbos 1211
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ discussion</a> of what color management is, and why we need it,
+ together with a brief overview of the ICC profile format.<br>
+ <br>
+ <h2 style="text-decoration: underline;">Operating Environments</h2>
+ <h2> </h2>
+ <p>Argyll is known to compile and run in at least the following
+ environments: </p>
+ 1) MSWindows XP system using Microsoft VC++ 6.0 compiler<br>
+ 2) MSWindows XP system using Microsoft VC++ 8.0 Express compiler +
+ Platform SDK Feb. 2003<br>
+ 3) MSWindows XP system using Microsoft VC++ 9.0 Express compiler +
+ Platform SDK Feb. 2003<br>
+ 4) MSWindows XP system using Microsoft VC++ 10.0 Express compiler +
+ Platform SDK Feb. 2003<br>
+ 5) MSWindows XP system using Microsoft VC++ 11.0 Express compiler<br>
+ 6) MSWindows XP system using the MingW port of the GCC compiler<br>
+ 7) Linux on Fedora Core 8, 32 bit using gcc <br>
+ 8) Linux on Fedora Core 8, 64 bit using gcc<br>
+ 9) Apple OS X 10.3 PPC using GCC<br>
+ 10) Apple OS X 10.4, 10.5, 10.6 Intel using GCC<br>
+ 11) Apple OS X10.7 Intel using&nbsp; Clang<br>
+ <br>
+ Additionally it is also known to run on:<br>
+ <br>
+ &nbsp;MSWindows 2000, Vista &amp; Windows 7 - 32 bit.<br>
+ &nbsp;MSWindows Vista 64bit, Windows 7, 8, 8.1, 10 - 64 bit.<br>
+ <p>but may well compile and run correctly in many more than this,
+ including OS X 10.8, 10.9, 10.10 and beyond.<br>
+ </p>
+ This is a <span style="font-weight: bold;">command line terminal</span>
+ only environment. Those unfamiliar with command line environments
+ should consult an appropriate tutorial for their environment if they
+ are interested in using this software. See the listing of <a
+ href="#cltutes">tutorials</a> below.<span style="font-weight:
+ bold;"></span><br>
+ <br>
+ The following color measuring instruments are directly supported:<br>
+ <br>
+ JETI:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#specbos">specbos 1211
&amp; 1201</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -210,10 +231,46 @@
- - Tele-Spectro-Radiometer<br>
- <br>
- Image Engineering:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Tele-Spectro-Radiometer<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#spectraval">spectraval
+ 1511&amp; 1501</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp; - Tele-Spectro-Radiometer<br>
+ <br>
+ Image Engineering:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#ex1">EX1</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -270,10 +327,33 @@
- - Tele-Spectro-Radiometer<br>
- <br>
- Klein:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Tele-Spectro-Radiometer<br>
+ <br>
+ Klein:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#k10a">K10-A</a>&nbsp;&nbsp;
@@ -307,13 +387,36 @@
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; - Display Colorimeter. Reported also to work with
- the K-1, K-8 and&nbsp; K-10.<br>
- <br>
- X-Rite:<br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; - Display Colorimeter. Reported also to work with
+ the K-1, K-8 and&nbsp; K-10.<br>
+ <br>
+ X-Rite:<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP20">DTP20 "Pulse"</a>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -412,8 +515,31 @@
- - "swipe" type reflective spectrometer, that can be used untethered.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP22">DTP22 Digital
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - "swipe" type reflective spectrometer, that can be used untethered.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP22">DTP22 Digital
Swatchbook</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -511,7 +637,30 @@
- - spot type reflective spectrometer.<br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot type reflective spectrometer.<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP41">DTP41</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -609,9 +758,32 @@
- - spot and strip reading reflective spectrometer.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP41">DTP41T</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot and strip reading reflective spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP41">DTP41T</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -709,7 +881,30 @@
- - spot and strip reading reflective/transmissive spectrometer.<br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot and strip reading reflective/transmissive spectrometer.<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#dtp51">DTP51</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -807,7 +1002,30 @@
- - strip reading reflective colorimeter.<br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - strip reading reflective colorimeter.<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP92">DTP92</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -905,68 +1123,91 @@
- - CRT display colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP94">DTP94</a> <font
- size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro"- display
- colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#ColorMunki"><span
- style="text-decoration: underline;">ColorMunki</span></a> Design
- or Photo&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
- spot and "swipe" reflective/emissive spectrometer (UV cut only).<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d"><span
- style="text-decoration: underline;">ColorMunki</span></a> Create
- or Smile&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
- colorimeter. (Similar to an Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Lenovo W</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -
- built in laptop Huey display colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d3">Eye-One Display
- 3</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - Xrite i1 DisplayPro and ColorMunki
- Display <br>
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
- i1Display Pro, NEC SpectraSensor Pro,<br>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM and HP
- DreamColor&nbsp; i1d3 are also reported to work.]<br>
- &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
- "swipe" reflective/emissive spectrometer.<br>
- <br>
- Gretag-Macbeth (now X-Rite):<br>
- &nbsp; &nbsp; <a href="instruments.html#sl">Spectrolino</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
- reflective/emissive spectrometer.<br>
- &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScan</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
- reflective/emissive, XY table reflective spectrometer&nbsp; .<br>
- &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScanT</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
- reflective/emissive/transmissive, XY table reflective spectrometer.<br>
- &nbsp; &nbsp; <a href="instruments.html#i1p">Eye-One Pro</a> "EFI
- ES-1000" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe"
- reflective/emissive spectrometer.<br>
- &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive
- spectrometer.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">Eye-One Display 1
- or 2&nbsp; or LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
- display colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
- APS</a>&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - CRT display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP94">DTP94</a> <font
+ size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro"- display
+ colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#ColorMunki"><span
+ style="text-decoration: underline;">ColorMunki</span></a> Design
+ or Photo&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
+ spot and "swipe" reflective/emissive spectrometer (UV cut only).<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d"><span
+ style="text-decoration: underline;">ColorMunki</span></a> Create
+ or Smile&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter. (Similar to an Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Lenovo W</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -
+ built in laptop Huey display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d3">Eye-One Display
+ 3</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - Xrite i1 DisplayPro and ColorMunki
+ Display <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
+ i1Display Pro, NEC SpectraSensor Pro,<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM and HP
+ DreamColor&nbsp; i1d3 are also reported to work.]<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
+ "swipe" reflective/emissive spectrometer.<br>
+ <br>
+ Gretag-Macbeth (now X-Rite):<br>
+ &nbsp; &nbsp; <a href="instruments.html#sl">Spectrolino</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScan</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive, XY table reflective spectrometer&nbsp; .<br>
+ &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScanT</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive/transmissive, XY table reflective spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p">Eye-One Pro</a> "EFI
+ ES-1000" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe"
+ reflective/emissive spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive
+ spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">Eye-One Display 1
+ or 2&nbsp; or LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
+ display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
+ APS</a>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1064,8 +1305,31 @@
- - display colorimeter. (Treated as a Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">CalMAN X2</a>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">CalMAN X2</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1163,17 +1427,40 @@
- - display colorimeter. (Treated as a Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Huey</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
- <br>
- Sequel imaging (Now X-Rite):<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#mox">MonacoOPTIX</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
- colorimeter (Treated as an Eye-One Display 1)<br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Huey</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ <br>
+ Sequel imaging (Now X-Rite):<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#mox">MonacoOPTIX</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter (Treated as an Eye-One Display 1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1271,9 +1558,33 @@
- [The Sequel Chroma 4 may also work.]<br>
- <br>
- Lacie Blue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [The Sequel Chroma 4 &amp; 5, and Sencore ColorPro V, IV &amp; III
+ also work.]<br>
+ <br>
+ Lacie Blue
Eye:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1371,14 +1682,37 @@
- - see <a href="instruments.html#i1d">Eye-One Display</a><br>
- <br>
- DataColor ColorVision:<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd2">Spyder 2</a>
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> firmware)<br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - see <a href="instruments.html#i1d">Eye-One Display</a><br>
+ <br>
+ DataColor ColorVision:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd2">Spyder 2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> firmware)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1476,28 +1810,6 @@
- [The Spyder 1 has also been reported as working, but this has not
- been confirmed.]<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd3">Spyder 3</a>
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd4">Spyder 4</a>
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> calibration
- data)<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd5">Spyder 5</a>
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> calibration
- data)<br>
- <br>
- Other:<br>
- &nbsp;&nbsp;&nbsp; <span class="titre"><a
- href="instruments.html#HCFR">Colorimètre HCFR</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1520,6 +1832,30 @@
+
+ [The Spyder 1 has also been reported as working, but this has not
+ been confirmed.]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd3">Spyder 3</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd4">Spyder 4</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd5">Spyder 5</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ <br>
+ Other:<br>
+ &nbsp;&nbsp;&nbsp; <span class="titre"><a
+ href="instruments.html#HCFR">Colorimètre HCFR</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
@@ -1594,8 +1930,6 @@
- - display colorimeter</span><br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#ColorHug">ColorHug</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1639,6 +1973,11 @@
+
+ - display colorimeter</span><br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#ColorHug">ColorHug</a>
+ and
+ ColorHug2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1647,6 +1986,9 @@
+
+ - display colorimeter<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#SMCube">Palette/SwatchMate
@@ -1674,57 +2016,57 @@
+
+ Cube</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- - display colorimeter<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#SMCube">Palette/SwatchMate
- Cube</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
- reflective colorimeter<br>
- <span style="font-weight: bold;"></span><span class="titre"><br>
- See </span><a href="instruments.html">Operation of particular
- instruments</a> for more instrument specific detail.<br>
- <br>
- Other instruments can be supported indirectly, since patch result
- files created by other packages can be imported into Argyll.<br>
- <br>
- Please <span style="font-weight: bold;">note</span> the <big><b><a
- href="Installing.html">installation instructions</a></b></big>
- for each platform - they contain important information for getting
- your instruments working.<br>
- <p>If you've decided to buy a color instrument because Argyll
- supports it, please let the dealer and manufacturer know that "<span
- style="font-weight: bold;">You bought it because Argyll CMS
- supports it</span>" - thanks.<br>
- </p>
- <p><span style="font-weight: bold;">Please note that instruments are
- being driven by ArgyllCMS drivers, and that any problems or
- queries regarding instrument<br>
- operation </span><span style="font-weight: bold;">should be
- directed to the Argyll's author(s) or the Argyll mailing list,
- and not to any</span> <span style="font-weight: bold;">other
- party.</span> </p>
- <p>There is a <a href="ccmxs.html">list of contributed</a> <span
- style="font-weight: bold;">ccmx</span> (Colorimeter Correction
- Matrix) files for some display/colorimeter combinations.</p>
- <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
- name="Copyright"></a>Copyright, Licensing &amp; Trade Mark:</span><br>
- </h2>
- <p>Most of the source code and provided executable files are
- copyrighted works, licensed under the <span style="font-weight:
- bold;">Affero GNU Version 3 license</span>, and therefore they
- (or works derived from them) can't be copied, sold or made
- available to users interacting with them remotely through a
- computer network, without providing the source code. Nothing other
- than your agreement and compliance with the Affero GNU License
- grants you permission to use, modify or distribute ArgyllCMS
- source code, executables or its derivative works. You could be
- sued for copyright infringement if you use or distribute ArgyllCMS
+
+ - reflective colorimeter<br>
+ <span style="font-weight: bold;"></span><span class="titre"><br>
+ See </span><a href="instruments.html">Operation of particular
+ instruments</a> for more instrument specific detail.<br>
+ <br>
+ Other instruments can be supported indirectly, since patch result
+ files created by other packages can be imported into Argyll.<br>
+ <br>
+ Please <span style="font-weight: bold;">note</span> the <big><b><a
+ href="Installing.html">installation instructions</a></b></big>
+ for each platform - they contain important information for getting
+ your instruments working.<br>
+ <p>If you've decided to buy a color instrument because Argyll
+ supports it, please let the dealer and manufacturer know that "<span
+ style="font-weight: bold;">You bought it because ArgyllCMS
+ supports it</span>" - thanks.<br>
+ </p>
+ <p><span style="font-weight: bold;">Please note that instruments are
+ being driven by ArgyllCMS drivers, and that any problems or
+ queries regarding instrument<br>
+ operation </span><span style="font-weight: bold;">should be
+ directed to the Argyll's author(s) or the Argyll mailing list,
+ and not to any</span> <span style="font-weight: bold;">other
+ party.</span> </p>
+ <p>There is a <a href="ccmxs.html">list of contributed</a> <span
+ style="font-weight: bold;">ccmx</span> (Colorimeter Correction
+ Matrix) files for some display/colorimeter combinations.</p>
+ <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
+ name="Copyright"></a>Copyright, Licensing &amp; Trade Mark:</span><br>
+ </h2>
+ <p>Most of the source code and provided executable files are
+ copyrighted works, licensed under the <span style="font-weight:
+ bold;">Affero GNU Version 3 license</span>, and therefore they
+ (or works derived from them) can't be copied, sold or made
+ available to users interacting with them remotely through a
+ computer network, without providing the source code. Nothing other
+ than your agreement and compliance with the Affero GNU License
+ grants you permission to use, modify or distribute ArgyllCMS
+ source code, executables or its derivative works. You could be
+ sued for copyright infringement if you use or distribute ArgyllCMS
without a valid license. The <span style="font-weight: bold;">Affero
@@ -1749,61 +2091,84 @@
- GNU</span> license <span style="font-weight: bold;">prohibits</span>
- extending these tools<span style="font-weight: bold;"></span>
- (i.e. by combining them with other programs or scripts that make
- use of, depend on, or work with the ArgyllCMS code) and
- distributing them, unless all the elements of the extensions are
- also made available under a GPL compatible license. It is
- permissible to provide ArgyllCMS tools with other non GPL
- components if the elements of the package are not related, such
- that the packaging is mere aggregation. For all the gory details,
- please read the accompanying <a href="License.txt">license</a>. </p>
- Note that unlike many commercial ICC profiling tools, the profiles
- created using ArgyllCMS, are not subject to any claims or
- restrictions of ArgyllCMS's author(s), but are assumed to be the
- copyright property of the person who gathers the characterization
- data, and causes the profiles to be created.
- <p>The ArgyllCMS is Copyright 1995 - 2015 Graeme W. Gill, and is
- made available under the terms of the Affero GNU General Public
- License Version 3, as detailed in the <a href="License.txt">License.txt</a>
- file. Documentation is licensed under the terms of the GNU Free
- Documentation License, Version 1.3. The author asserts his moral
- rights over this material in relationship to the attribution and
- integrity of these works. In particular, if these works are
- modified in a way that materially changes their functionality,
- then the modified works should be renamed in a way that clearly
- distinguishes them from "Argyll" or "ArgyllCMS" so that the
- effects of such changes do not reflect on the original works
- integrity or the original authors reputation. A subset of files
- (those that are related to the color instrument drivers, and are
- collected together into the instlib.zip archive by the
- spectro/instlib.ksh script + xicc/ccmx.h and xicc/ccmx.c) are
- licensed under the General Public License Version 2 or later, as
- detailed in the <a href="License2.txt">License2.txt</a> file.<br>
- </p>
- <p>Portions of the ColorHug instrument library
- (spectro/colorhug.[ch]) are Copyright 2011, Richard Hughes, and is
- licensed under the General Public License Version 2 or later, as
- detailed in the <a href="License2.txt">License2.txt</a> file.</p>
- <p>The tool spectro/spec2cie.c is Copyright 2005 Gerhard Fuernkranz,
- and is made available under the terms of the GNU General Public
- License Version 2 or later, and is licensed here under the Version
- 3 license, as detailed in the <a href="License3.txt">License3.txt</a>
- file.<br>
- </p>
- <p>The Win32 USB library libusb-win32 kernel drivers are included in
- this distribution in the usb/driver and usb/bin directories, and
- are copyright Stephan Meyer and Travis Robinson, and are licensed
- under the GNU Version 2 or later (the drivers, services,
- installer). See&nbsp; usb/driver/License.txt,
- libusbw/COPYING_LGPL.txt and libusbw/COPYING_GPL.txt for details.
- Additional terms noted on the <a
- href="http://sourceforge.net/apps/trac/libusb-win32/wiki">website</a>
- are "This license combination explicitly allows the use of this
- library in commercial, non-Open-Source applications."<br>
- </p>
- <p>The icc library in<span style="font-weight: bold;"> icc</span>/,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GNU</span> license <span style="font-weight: bold;">prohibits</span>
+ extending these tools<span style="font-weight: bold;"></span>
+ (i.e. by combining them with other programs or scripts that make
+ use of, depend on, or work with the ArgyllCMS code) and
+ distributing them, unless all the elements of the extensions are
+ also made available under a GPL compatible license. It is
+ permissible to provide ArgyllCMS tools with other non GPL
+ components if the elements of the package are not related, such
+ that the packaging is mere aggregation. For all the gory details,
+ please read the accompanying <a href="License.txt">license</a>. </p>
+ Note that unlike many commercial ICC profiling tools, the profiles
+ created using ArgyllCMS, are not subject to any claims or
+ restrictions of ArgyllCMS's author(s), but are assumed to be the
+ copyright property of the person who gathers the characterization
+ data, and causes the profiles to be created.
+ <p>The ArgyllCMS is Copyright 1995 - 2016 Graeme W. Gill, and is
+ made available under the terms of the Affero GNU General Public
+ License Version 3, as detailed in the <a href="License.txt">License.txt</a>
+ file. Documentation is licensed under the terms of the GNU Free
+ Documentation License, Version 1.3. The author asserts his moral
+ rights over this material in relationship to the attribution and
+ integrity of these works. In particular, if these works are
+ modified in a way that materially changes their functionality,
+ then the modified works should be renamed in a way that clearly
+ distinguishes them from "Argyll" or "ArgyllCMS" so that the
+ effects of such changes do not reflect on the original works
+ integrity or the original authors reputation.<br>
+ A subset of files (those that are related to the color instrument
+ drivers, and are collected together into the instlib.zip archive
+ by the spectro/instlib.ksh script + xicc/ccmx.h and xicc/ccmx.c)
+ are licensed under the General Public License Version 2 or later,
+ as detailed in the <a href="License2.txt">License2.txt</a> file.<br>
+ </p>
+ <p>Portions of the ColorHug instrument library
+ (spectro/colorhug.[ch]) are Copyright 2011, Richard Hughes, and is
+ licensed under the General Public License Version 2 or later, as
+ detailed in the <a href="License2.txt">License2.txt</a> file.</p>
+ <p>The tool spectro/spec2cie.c is Copyright 2005 Gerhard Fuernkranz,
+ and is made available under the terms of the GNU General Public
+ License Version 2 or later, and is licensed here under the Version
+ 3 license, as detailed in the <a href="License3.txt">License3.txt</a>
+ file.<br>
+ </p>
+ <p>The Win32 USB library libusb-win32 kernel drivers are included in
+ this distribution in the usb/driver and usb/bin directories, and
+ are copyright Stephan Meyer and Travis Robinson, and are licensed
+ under the GNU Version 2 or later (the drivers, services,
+ installer). See&nbsp; usb/driver/License.txt,
+ libusbw/COPYING_LGPL.txt and libusbw/COPYING_GPL.txt for details.
+ Additional terms noted on the <a
+ href="http://sourceforge.net/apps/trac/libusb-win32/wiki">website</a>
+ are "This license combination explicitly allows the use of this
+ library in commercial, non-Open-Source applications."<br>
+ </p>
+ <p>The icc library in<span style="font-weight: bold;"> icc</span>/,
the CGATS library in <span style="font-weight: bold;">cgats</span>/,
@@ -1901,6 +2266,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
the jcnf library in <span style="font-weight: bold;">jcnf</span>/,
@@ -1997,91 +2385,117 @@
- the files <span style="font-weight: bold;">spectro/xdg_bds.*</span>,
- <span style="font-weight: bold;">spectro/aglob.*</span> and the
- ucmm library in <span style="font-weight: bold;">ucmm</span>/ are
- Copyright 1995 - 2015 Graeme W. Gill, and available according to
- the "MIT" license granted in the icc/License.txt and
- cgats/License.txt files, and the licenses at the top of
- ucmm/ucmm.c and jcnf/jcnf.c.<br>
- </p>
- <p>The yajl library in <span style="font-weight: bold;">jcnf/yajl</span>
- is Copyright (c) 2007-2014, Lloyd Hilaiel &lt;me@lloyd.io&gt; and
- is used under an ISC License granted in the yajl/COPYING files.
- The yajl library has been repackaged and modified slightly to adds
- some features and for packaging and build convenience.<br>
- </p>
- <p> The TIFF library included in this distribution for convenience,
- has its own copyright and license detailed in tiff/COPYRIGHT (an
- "MIT"/"BSD" like license).<br>
- </p>
- <p>The Independent JPEG Group's JPEG library included in this
- distribution for convenience, has its own copyright and license
- detailed in jpg/README (an "MIT"/"BSD" like license). Executables
- that include JPEG format support are based in part on the work of
- the Independent JPEG Group. </p>
- <p>xicc/iccjpeg.h and xicc/iccjpeg.c are from <a
- href="http://www.littlecms.com/">lcms</a> and they are Copyright
- (c) 1998-2010 Marti Maria Saguer and is licensed under an
- "MIT"/"BSD" like license. See the top of the iccjpeg.c file for
- the detailed copyright and licensing conditions.<br>
- </p>
- <p>The mongoose web server software is Copyright (c) 2004-2011
- Sergey Lyubka, and is licensed under an "MIT" license.<br>
- </p>
- <p>The axTLS library is Copyright (c) 2008, Cameron Rich, and the
- license is detailed in ccast/axTLS/LICENSE file (an "MIT"/"BSD"
- like license).<br>
- It is not used for any security sensitive purpose, but is used
- purely to communicate with the ChromeCast.<br>
- </p>
- <p>The <a href="http://www.x3dom.org/">X3DOM</a> x3dom.css and
- x3dom.js files are Copyright (C) 2009 X3DOM and licensed dual
- "MIT" and "GPL" license. See plot/X3DOM_LICENSE.txt.<br>
- </p>
- <p>"<b>ArgyllCMS</b>" is a trade mark. It is permissible to refer to
- copies or derivatives of this software as being the same as
- ArgyllCMS if they are materially&nbsp; unchanged, and retain all
- the functionality provided by the software made available at
- www.argyllcms.com. Modified versions of this software that are
- materially changed or have missing functionality must be clearly
- marked as such, so as not to to be confused with ArgyllCMS.<br>
- </p>
- <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
- name="ProjType"></a>What sort of project is this ? (re:
- contributions)<br>
- </span></h2>
- This is essentially my private project, that I've made available
- under GNU licensing conditions. Because I license my code under
- other licenses as well, there is a limit to what I will accept in
- the way of code contributions back into this project. For me to
- accept contributions into the distribution, it either has to a
- non-core (side) project, or has to be offered to me with copyright
- conditions that are compatible with my other uses (i.e.. a "BSD"
- like license, or assigning or licensing the copyright to me), or has
- to be so trivial (say a one line bug fix), that it can't be the
- subject of copyright. <br>
- <br>
- Of course there is nothing to stop someone setting up a real free
- software, community project based on the GNU licensed code made
- available here, that would be able to take GNU licensed
- contributions from everyone and would essentially be a "fork" of
- this code base.<br>
- <br>
- <h1><u><a href="Compiling.html">Compiling</a></u></h1>
- How to <a href="Compiling.html">build the software</a> from the
- source if you want to.<br>
- <span style="font-weight: bold;">Note</span> that you don't need to
- do this if you are using one of the binary installations.<br>
- <h1 style="color: rgb(51, 204, 0);"><u><a href="Installing.html">Installing</a></u></h1>
- Important notes on <a href="Installing.html">installing the binary
- software</a> on various platforms.<br>
- <br>
- <h2 style="color: rgb(51, 0, 51);"><u><u><a name="GUIs"></a>Graphic
- User Interfaces<br>
- </u></u></h2>
- ArgyllCMS does not directly support a graphic user interface, but
- several people have written <span style="font-weight: bold;">GUI</span>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the files <span style="font-weight: bold;">spectro/xdg_bds.*</span>,
+ <span style="font-weight: bold;">spectro/aglob.*</span> and the
+ ucmm library in <span style="font-weight: bold;">ucmm</span>/ are
+ Copyright 1995 - 2015 Graeme W. Gill, and available according to
+ the "MIT" permissive free software license granted in the <a
+ href="License4.txt">License4.txt</a> file, and the licenses at
+ the top of ucmm/ucmm.c and jcnf/jcnf.c.<br>
+ </p>
+ <p>The yajl library in <span style="font-weight: bold;">yajl</span>/
+ is Copyright (c) 2007-2014, Lloyd Hilaiel &lt;me@lloyd.io&gt; and
+ is used under an ISC permissive free software license granted in
+ the yajl/COPYING files. The yajl library has been repackaged and
+ modified slightly to adds some features and for packaging and
+ build convenience.<br>
+ </p>
+ <p> The TIFF library included in this distribution for convenience,
+ has its own copyright and license detailed in tiff/COPYRIGHT (an
+ "MIT"/"BSD" like permissive free software license).<br>
+ </p>
+ <p>The Independent JPEG Group's JPEG library included in this
+ distribution for convenience, has its own copyright and license
+ detailed in jpg/README (an "MIT"/"BSD" like permissive free
+ software license). Executables that include JPEG format support
+ are based in part on the work of the Independent JPEG Group. </p>
+ <p>xicc/iccjpeg.h and xicc/iccjpeg.c are from <a
+ href="http://www.littlecms.com/">lcms</a> and they are Copyright
+ (c) 1998-2010 Marti Maria Saguer and is licensed under an
+ "MIT"/"BSD" like permissive free software license. See the top of
+ the iccjpeg.c file for the detailed copyright and licensing
+ conditions.<br>
+ </p>
+ <p>The mongoose web server software is Copyright (c) 2004-2011
+ Sergey Lyubka, and is licensed under an "MIT" permissive free
+ software license.<br>
+ </p>
+ <p>The axTLS library is Copyright (c) 2008, Cameron Rich, and the
+ license is detailed in ccast/axTLS/LICENSE file (an "MIT"/"BSD"
+ like permissive free software license).<br>
+ It is not used for any security sensitive purpose, but is used
+ purely to communicate with the ChromeCast.<br>
+ </p>
+ <p>The <a href="http://www.x3dom.org/">X3DOM</a> x3dom.css and
+ x3dom.js files are Copyright (C) 2009 X3DOM and licensed dual
+ "MIT" permissive free software and "GPL" license. See
+ plot/X3DOM_LICENSE.txt.<br>
+ </p>
+ <p>"<b>ArgyllCMS</b>" is a trade mark. It is permissible to refer to
+ copies or derivatives of this software as being the same as
+ ArgyllCMS if they are materially&nbsp; unchanged, and retain all
+ the functionality provided by the software made available at
+ www.argyllcms.com. Modified versions of this software that are
+ materially changed or have missing functionality must be clearly
+ marked as such, so as not to to be confused with ArgyllCMS.<br>
+ </p>
+ <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
+ name="ProjType"></a>What sort of project is this ? (re:
+ contributions)<br>
+ </span></h2>
+ This is essentially my private project, that I've made available
+ under GNU licensing conditions. Because I license my code under
+ other licenses as well, there is a limit to what I will accept in
+ the way of code contributions back into this project. For me to
+ accept contributions into the distribution, it either has to a
+ non-core (side) project, or has to be offered to me with copyright
+ conditions that are compatible with my other uses (i.e.. a "BSD" or
+ "MIT"&nbsp; like permissive free software license, or assigning or
+ licensing the copyright to me), or has to be so trivial (say a one
+ line bug fix), that it can't be the subject of copyright. <br>
+ <br>
+ Of course there is nothing to stop someone setting up a real free
+ software, community project based on the GNU licensed code made
+ available here, that would be able to take GNU licensed
+ contributions from everyone and would essentially be a "fork" of
+ this code base.<br>
+ <h1><u><a href="Compiling.html">Compiling</a></u></h1>
+ How to <a href="Compiling.html">build the software</a> from the
+ source if you want to.<br>
+ <span style="font-weight: bold;">Note</span> that you don't need to
+ do this if you are using one of the binary installations.<br>
+ <h1 style="color: rgb(51, 204, 0);"><u><a href="Installing.html">Installing</a></u></h1>
+ Important notes on <a href="Installing.html">installing the binary
+ software</a> on various platforms.<br>
+ <br>
+ <h2 style="color: rgb(51, 0, 51);"><u><u><a name="GUIs"></a>Graphic
+ User Interfaces<br>
+ </u></u></h2>
+ ArgyllCMS does not directly support a graphic user interface, but
+ several people have written <span style="font-weight: bold;">GUI</span>
based front ends for it. A popular <span style="font-weight: bold;"></span>front
end
that
@@ -2184,17 +2598,65 @@ calibration
- and profiling is <a href="http://hoech.net/dispcalGUI/">dispcalGUI</a>
- by Florian Höch. Others can be found with a suitable <a
-href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;aq=f&amp;aqi=g1&amp;aql=&amp;oq=">search</a>.<br>
- <h2 style="color: rgb(51, 0, 51);"><u><a name="CmdLine"></a>Main
- Tools and the command line<br>
- </u></h2>
- These are all command line ("DOS" shell) tools, and each tool
- require appropriate options to be set, followed by filename
- arguments. Sometimes the filenames will have to include the usual
- extensions, sometimes they are implicit. To get a brief listing of
- the possible arguments and <span style="font-weight: bold;">usage</span>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and profiling is <a href="http://displaycal.net/">DisplayCAL</a> by
+ Florian Höch. For print profiling, you might like to take a look at
+ <a href="http://www.russellcottrell.com/photo/LittleArgyllGUI.asp">The
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Little Argyll GUI</a> by Russell Cottrell, and for cameras or
+ scanners, <a href="http://www.muscallidus.com/coca/">CoCa</a> by
+ Andrew Stawowczyk Long.<br>
+ <br>
+ Others can be found with a suitable <a
+href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;aq=f&amp;aqi=g1&amp;aql=&amp;oq=">search</a>.<br>
+ <h2 style="color: rgb(51, 0, 51);"><u><a name="CmdLine"></a>Main
+ Tools and the command line<br>
+ </u></h2>
+ These are all command line ("DOS" shell) tools, and each tool
+ require appropriate options to be set, followed by filename
+ arguments. Sometimes the filenames will have to include the usual
+ extensions, sometimes they are implicit. To get a brief listing of
+ the possible arguments and <span style="font-weight: bold;">usage</span>
of any of the tools, run it with just an "-?" argument, i.e. <b>targen
@@ -2290,22 +2752,45 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
- -? </b>(or some other unrecognized flag, if the "?" character is
- treated specially in your shell, i.e. try "--" on OS X zsh).<br>
- <br>
- Note that in general the arguments consist of possible flags or
- options followed by file name arguments. All arguments need to be
- separated by whitespace.&nbsp; (If you need to specify a string with
- embedded white space, double quote the string). A flag consists of a
- dash attached to a single letter, the letter identifying the flag,
- and is usually case sensitive. An option is a flag that has an
- associated parameter or parameters. The parameter can be separated
- from the flag by white space, or may come directly after the flag.
- So if a tool has a usage that looks like this:<br>
- <br>
- &nbsp; tool -?<br>
- &nbsp; usage: tool [options] infile outfile<br>
- &nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -? </b>(or some other unrecognized flag, if the "?" character is
+ treated specially in your shell, i.e. try "--" on OS X zsh).<br>
+ <br>
+ Note that in general the arguments consist of possible flags or
+ options followed by file path+name arguments. All arguments need to
+ be separated by whitespace.&nbsp; (If you need to specify a string
+ with embedded white space, double quote the string). A flag consists
+ of a dash attached to a single letter, the letter identifying the
+ flag, and is usually case sensitive. An option is a flag that has an
+ associated parameter or parameters. The parameter can be separated
+ from the flag by white space, or may come directly after the flag.
+ So if a tool has a usage that looks like this:<br>
+ <br>
+ &nbsp; tool -?<br>
+ &nbsp; usage: tool [options] infile outfile<br>
+ &nbsp;&nbsp;
-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2403,8 +2888,31 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
- Verbose mode<br>
- &nbsp;&nbsp; -d
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Verbose mode<br>
+ &nbsp;&nbsp; -d
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2502,8 +3010,31 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
- Choose a depth 0-4<br>
- &nbsp;&nbsp; -r
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Choose a depth 0-4<br>
+ &nbsp;&nbsp; -r
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2601,11 +3132,34 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
- Use a random depth<br>
- &nbsp;&nbsp; -f
- [nn]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Use full range. nn optional range 0 - 100.<br>
- &nbsp;&nbsp; -M
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use a random depth<br>
+ &nbsp;&nbsp; -f
+ [nn]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Use full range. nn optional range 0 - 100.<br>
+ &nbsp;&nbsp; -M
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2703,8 +3257,31 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
- Manual<br>
- &nbsp;&nbsp; infile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Manual<br>
+ &nbsp;&nbsp; infile
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2802,159 +3379,182 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
- Input file<br>
- &nbsp;&nbsp; outfile
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Output file<br>
- <br>
- then there are&nbsp; 5 flags/options, and two filename arguments.
- Notice that square braces [] denote optional items. The first
- flag/option is a flag. The second is an option that has a numerical
- argument in the range 0 to 4. The third is a flag. the fourth is an
- option with an optional argument. The fourth is a flag.&nbsp; The
- flags and options can generally be in any order, but must be before
- the file name arguments. (For a few special tools you actually
- specify a sequence of flags and files where the flags apply just to
- the following file.) So example invocations may look like:<br>
- <br>
- &nbsp; tool -v testin testout<br>
- &nbsp; tool -d3 -M testin1 testout2<br>
- &nbsp; tool -f infile outfile<br>
- &nbsp; tool -f 45 infile outfile<br>
- &nbsp; tool -d 3 -f67 infile outfile<br>
- <p>In order to make use of the tools, it is necessary to keep track
- of where various files are, and what they are called. There are
- many possible ways of doing this. One way is to put each source
- profile and all its associated files (test charts, spectrometer
- values etc.) in one set of directories for each source profile
- type. Similarly the device profiles could be stored in a hierarchy
- of directories ordered by device type, media, resolution, device
- mode etc. Naturally you will want to set your $PATH so that you
- can run the tools from whichever directory you are in, as well as
- specify any necessary directory paths for file arguments so that
- the tools are able to open them.<br>
- </p>
- <p>Note that there are two ways the Argyll tools deal with filename
- extensions. In one you supply the extension (ie. you supply the
- whole file name), so the extension is up to you. In the other
- (used where one name is used for input and output files, or where
- there are multiple output files), the program adds the extension.
- In the documentation this should be indicated by calling it a
- "base name".<br>
- </p>
- <p><a name="cltutes"></a>For more information on using a command
- line environments, consult an appropriate tutorial:</p>
- <p>MS Windows :<br>
- &nbsp;&nbsp; &lt;<a
- href="http://www.bleepingcomputer.com/tutorials/tutorial76.html">http://www.bleepingcomputer.com/tutorials/tutorial76.html</a>&gt;<br>
- &nbsp;&nbsp; &lt;<a
- href="http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1">http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1</a>&gt;<br>
- &nbsp;&nbsp; &lt;<a
- href="http://www.voidspace.org.uk/python/articles/command_line.shtml">http://www.voidspace.org.uk/python/articles/command_line.shtml</a>&gt;<br>
- <br>
- &nbsp;&nbsp;&nbsp; To find more: &lt;<a
-href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial&gt;</a><br>
- <br>
- OS X:<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.osxfaq.com/Tutorials/LearningCenter/">http://www.osxfaq.com/Tutorials/LearningCenter/</a>&gt;<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.atomiclearning.com/macosxterminalx.shtml">http://www.atomiclearning.com/macosxterminalx.shtml</a>&gt;<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html">http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html</a>&gt;<br>
- <br>
- &nbsp;&nbsp;&nbsp; To find more: &lt;<a
- href="http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial">http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial</a>&gt;<br>
- <br>
- Linux:<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.linuxcommand.org/index.php">http://www.linuxcommand.org/index.php</a>&gt;<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.tuxfiles.org/linuxhelp/shell.html">http://www.tuxfiles.org/linuxhelp/shell.html</a>&gt;<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.ee.surrey.ac.uk/Teaching/Unix/">http://www.ee.surrey.ac.uk/Teaching/Unix/</a>&gt;<br>
- <br>
- &nbsp;&nbsp;&nbsp; To find more: &lt;<a
- href="http://www.google.com/search?q=linux+command+line+shell+tutorial">http://www.google.com/search?q=linux+command+line+shell+tutorial</a>&gt;</p>
- <p><br>
- <span style="font-weight: bold;">Note</span> that since OS X is
- based on UNIX, there is much in common between the OS X and Linux
- command line environments, and many of the UNIX tutorials may be
- useful:<br>
- </p>
- <p>&nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.rain.org/%7Emkummel/unix.html">http://www.rain.org/~mkummel/unix.html</a>&gt;<br>
- <br>
- </p>
- <h2><u><a href="Scenarios.html">Tutorial: Typical usage scenarios
- and examples</a></u></h2>
- A <a href="Scenarios.html">guided tour</a> of the major tools,
- applied to typical CMS jobs, such as calibrating displays, creating
- device profiles, calibrating printers, linking profiles, and
- converting color spaces of raster files. <br>
- <br>
- Although it is is a couple of years old now, this <a
- href="http://www.argyllcms.com/doc2/FCMS2010_ArgyllTute.pdf">tutorial</a>
- may also be of interest.<br>
- &nbsp; <br>
- <h3 style="color: rgb(0, 0, 0);"><u><a name="Topics"></a>Topical
- Discussions</u></h3>
- Discussions about particular topics:<br>
- <br>
- <a href="FWA.html">About Fluorescent Whitening Agent compensation</a><br>
- <br>
- <a href="instruments.html">Operation of particular instruments</a><br>
- <br>
- <a href="iccgamutmapping.html">About ICC profiles and Gamut Mapping</a><br>
- <br>
- <a href="monitorcontrols.html">About display monitor settings and
- targets</a><br>
- <br>
- <a href="gamma.html">About display "Gamma"</a><br>
- <br>
- <a href="calvschar.html">What's the difference between Calibration
- and Characterization ?</a><br>
- <br>
- <a href="WideGamutColmters.html">Why doesn't my Colorimeter work
- well on my Wide Gamut display ?</a><br>
- <span style="font-family: monospace;"></span><br>
- <a href="CrushedDisplyBlacks.html">My blacks get crushed on my
- display - why ? How do I fix it ?</a><br>
- <br>
- <a href="i1proDriver.html">How can I have confidence in the i1pro
- Driver ?</a><br>
- <br>
- <a href="i1proHiRes.html">Does the i1pro High Resolution mode
- improve accuracy ?</a><br>
- <br>
- <a href="evalInputTargets.html">Evaluating input targets</a><br>
- <br>
- <a href="ArgyllCMS_arts_tag.html">ArgyllCMS's Absolute to media
- Relative Transform Space matrix ('arts') ICC tag</a><br>
- <br>
- <h2><b><u><font><b><u><font size="+2"><a name="Flow"></a>Flow
- diagram of Major Tools:</font></u></b></font></u></b></h2>
- <br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a
- href="ArgyllFlow.jpg"><img alt="Thumbnail of Flow Diagram"
- src="ArgyllFlowThumb.jpg" style="border: 2px solid ; width:
- 150px; height: 202px;"></a><br>
- <br>
- <h2><b><u><font size="+2"><a name="CatList"></a>Main Tools by
- category:</font></u></b></h2>
- <h3>Calibrating devices<br>
- </h3>
- <small><a style="font-family: monospace;" href="dispcal.html">dispcal</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></small>Adjust,
- calibrate and profile a display<small><big>.<br>
- </big></small><small><a style="font-family: monospace;"
- href="printcal.html">printcal</a><span style="font-family:
- monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create a
- printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
- <h3>Creating test targets for profiling or print calibration<br>
- </h3>
- <small><a style="font-family: monospace;" href="targen.html">targen</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Input file<br>
+ &nbsp;&nbsp; outfile
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Output file<br>
+ <br>
+ then there are&nbsp; 5 flags/options, and two filename arguments.
+ Notice that square braces [] denote optional items. The first
+ flag/option is a flag. The second is an option that has a numerical
+ argument in the range 0 to 4. The third is a flag. the fourth is an
+ option with an optional argument. The fourth is a flag.&nbsp; The
+ flags and options can generally be in any order, but must be before
+ the file name arguments. (For a few special tools you actually
+ specify a sequence of flags and files where the flags apply just to
+ the following file.) So example invocations may look like:<br>
+ <br>
+ &nbsp; tool -v testin testout<br>
+ &nbsp; tool -d3 -M testin1 testout2<br>
+ &nbsp; tool -f infile outfile<br>
+ &nbsp; tool -f 45 infile outfile<br>
+ &nbsp; tool -d 3 -f67 infile outfile<br>
+ <p>In order to make use of the tools, it is necessary to keep track
+ of where various files are, and what they are called. There are
+ many possible ways of doing this. One way is to put each source
+ profile and all its associated files (test charts, spectrometer
+ values etc.) in one set of directories for each source profile
+ type. Similarly the device profiles could be stored in a hierarchy
+ of directories ordered by device type, media, resolution, device
+ mode etc. Naturally you will want to set your $PATH so that you
+ can run the tools from whichever directory you are in, as well as
+ specify any necessary directory paths for file arguments so that
+ the tools are able to open them.<br>
+ </p>
+ <p>Note that there are two ways the Argyll tools deal with filename
+ extensions. In one you supply the extension (ie. you supply the
+ whole file name), so the extension is up to you. In the other
+ (used where one name is used for input and output files, or where
+ there are multiple output files), the program adds the extension.
+ In the documentation this should be indicated by calling it a
+ "base name".<br>
+ </p>
+ <p><a name="cltutes"></a>For more information on using a command
+ line environments, consult an appropriate tutorial:</p>
+ <p>MS Windows :<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.bleepingcomputer.com/tutorials/tutorial76.html">http://www.bleepingcomputer.com/tutorials/tutorial76.html</a>&gt;<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1">http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1</a>&gt;<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.voidspace.org.uk/python/articles/command_line.shtml">http://www.voidspace.org.uk/python/articles/command_line.shtml</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial&gt;</a><br>
+ <br>
+ OS X:<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.osxfaq.com/Tutorials/LearningCenter/">http://www.osxfaq.com/Tutorials/LearningCenter/</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.atomiclearning.com/macosxterminalx.shtml">http://www.atomiclearning.com/macosxterminalx.shtml</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html">http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+ href="http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial">http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial</a>&gt;<br>
+ <br>
+ Linux:<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.linuxcommand.org/index.php">http://www.linuxcommand.org/index.php</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.tuxfiles.org/linuxhelp/shell.html">http://www.tuxfiles.org/linuxhelp/shell.html</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.ee.surrey.ac.uk/Teaching/Unix/">http://www.ee.surrey.ac.uk/Teaching/Unix/</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+ href="http://www.google.com/search?q=linux+command+line+shell+tutorial">http://www.google.com/search?q=linux+command+line+shell+tutorial</a>&gt;</p>
+ <p><br>
+ <span style="font-weight: bold;">Note</span> that since OS X is
+ based on UNIX, there is much in common between the OS X and Linux
+ command line environments, and many of the UNIX tutorials may be
+ useful:<br>
+ </p>
+ <p>&nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.rain.org/%7Emkummel/unix.html">http://www.rain.org/~mkummel/unix.html</a>&gt;<br>
+ <br>
+ </p>
+ <h2><u><a href="Scenarios.html">Tutorial: Typical usage scenarios
+ and examples</a></u></h2>
+ A <a href="Scenarios.html">guided tour</a> of the major tools,
+ applied to typical CMS jobs, such as calibrating displays, creating
+ device profiles, calibrating printers, linking profiles, and
+ converting color spaces of raster files. <br>
+ <br>
+ Although it is is a couple of years old now, this <a
+ href="http://www.argyllcms.com/doc2/FCMS2010_ArgyllTute.pdf">tutorial</a>
+ may also be of interest.<br>
+ &nbsp; <br>
+ <h3 style="color: rgb(0, 0, 0);"><u><a name="Topics"></a>Topical
+ Discussions</u></h3>
+ Discussions about particular topics:<br>
+ <br>
+ <a href="FWA.html">About Fluorescent Whitening Agent compensation</a><br>
+ <br>
+ <a href="instruments.html">Operation of particular instruments</a><br>
+ <br>
+ <a href="iccgamutmapping.html">About ICC profiles and Gamut Mapping</a><br>
+ <br>
+ <a href="monitorcontrols.html">About display monitor settings and
+ targets</a><br>
+ <br>
+ <a href="gamma.html">About display "Gamma"</a><br>
+ <br>
+ <a href="calvschar.html">What's the difference between Calibration
+ and Characterization ?</a><br>
+ <br>
+ <a href="WideGamutColmters.html">Why doesn't my Colorimeter work
+ well on my Wide Gamut display ?</a><br>
+ <span style="font-family: monospace;"></span><br>
+ <a href="CrushedDisplyBlacks.html">My blacks get crushed on my
+ display - why ? How do I fix it ?</a><br>
+ <br>
+ <a href="i1proDriver.html">How can I have confidence in the i1pro
+ Driver ?</a><br>
+ <br>
+ <a href="i1proHiRes.html">Does the i1pro High Resolution mode
+ improve accuracy ?</a><br>
+ <br>
+ <a href="evalInputTargets.html">Evaluating input targets</a><br>
+ <br>
+ <a href="ArgyllCMS_arts_tag.html">ArgyllCMS's Absolute to media
+ Relative Transform Space matrix ('arts') ICC tag</a><br>
+ <br>
+ <h2><b><u><font><b><u><font size="+2"><a name="Flow"></a>Flow
+ diagram of Major Tools:</font></u></b></font></u></b></h2>
+ <br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a
+ href="ArgyllFlow.jpg"><img alt="Thumbnail of Flow Diagram"
+ src="ArgyllFlowThumb.jpg" style="border: 2px solid ; width:
+ 150px; height: 202px;"></a><br>
+ <br>
+ <h2><b><u><font size="+2"><a name="CatList"></a>Main Tools by
+ category:</font></u></b></h2>
+ <h3>Calibrating devices<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="dispcal.html">dispcal</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></small>Adjust,
+ calibrate and profile a display<small><big>.<br>
+ </big></small><small><a style="font-family: monospace;"
+ href="printcal.html">printcal</a><span style="font-family:
+ monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create a
+ printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
+ <h3>Creating test targets for profiling or print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="targen.html">targen</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3052,9 +3652,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span><big>Generate a profiling test target values .ti1 file. </big><br
- style="font-family: monospace;">
- <a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Generate a profiling test target values .ti1 file. </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Create
@@ -3152,9 +3775,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- film recorder TIFF files from Argyll .ti1 file. </big><br
- style="font-family: monospace;">
- <a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ film recorder TIFF files from Argyll .ti1 file. </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Create
@@ -3252,11 +3898,34 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a PS, EPS or TIFF file containing test patch values, ready for
- printing.</big></small>
- <h3>Obtaining test results for profiling or print calibration<br>
- </h3>
- <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a PS, EPS or TIFF file containing test patch values, ready for
+ printing.</big></small>
+ <h3>Obtaining test results for profiling or print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Read
@@ -3354,10 +4023,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a test chart using an instrument to create a .ti3 data file.</big><span
- style="font-family: monospace;"> </span><br style="font-family:
- monospace;">
- <a style="font-family: monospace;" href="dispread.html">dispread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a test chart using an instrument to create a .ti3 data file.</big><span
+ style="font-family: monospace;"> </span><br style="font-family:
+ monospace;">
+ <a style="font-family: monospace;" href="dispread.html">dispread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Test
@@ -3455,9 +4147,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- and read colorimetric values from a display </big><br
- style="font-family: monospace;">
- <a style="font-family: monospace;" href="filmread.html">filmread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and read colorimetric values from a display </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="filmread.html">filmread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Read
@@ -3555,9 +4270,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- film colorimetric values using a SpectroScanT (Deprecated ?)</big><br
- style="font-family: monospace;">
- <a style="font-family: monospace;" href="scanin.html">scanin</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ film colorimetric values using a SpectroScanT (Deprecated ?)</big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="scanin.html">scanin</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3655,14 +4393,37 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span><big>Convert a TIFF&nbsp; image of a test chart into .ti3
- device values. <br>
- </big></small><small><a style="font-family: monospace;"
- href="illumread.html">illumread</a><span style="font-family:
- monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use an
- instrument to measure an illuminant spectrum, and estimate its UV
- content.<br style="font-family: monospace;">
- <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Convert a TIFF&nbsp; image of a test chart into .ti3
+ device values. <br>
+ </big></small><small><a style="font-family: monospace;"
+ href="illumread.html">illumread</a><span style="font-family:
+ monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use an
+ instrument to measure an illuminant spectrum, and estimate its UV
+ content.<br style="font-family: monospace;">
+ <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake
@@ -3760,13 +4521,36 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- the reading of a device using an ICC or MPP profile. <br>
- </big></small><small><a style="font-family: monospace;"
- href="synthread.html">synthread</a><span style="font-family:
- monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake the
- reading of a device using a synthetic device model. </big></small><br
- style="font-family: monospace;">
- <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the reading of a device using an ICC or MPP profile. <br>
+ </big></small><small><a style="font-family: monospace;"
+ href="synthread.html">synthread</a><span style="font-family:
+ monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake the
+ reading of a device using a synthetic device model. </big></small><br
+ style="font-family: monospace;">
+ <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3864,10 +4648,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span><big>Convert Colorblind format CMY/RGB test chart into
- Argyll .ti3 CGATS format. </big><br style="font-family:
- monospace;">
- <a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Convert Colorblind format CMY/RGB test chart into
+ Argyll .ti3 CGATS format. </big><br style="font-family:
+ monospace;">
+ <a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Convert
@@ -3965,9 +4772,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
- format. </big><br style="font-family: monospace;">
- <a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
+ format. </big><br style="font-family: monospace;">
+ <a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4065,11 +4895,34 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span><big>Convert Gretag/Logo/X-Rite/Barbieri or other format
- RGB or CMYK test chart results into Argyll .ti3 CGATS format. </big></small><br
- style="font-family: monospace;">
- <small><big><small><a style="font-family: monospace;"
- href="ls2ti3.html">ls2ti3</a><span style="font-family:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Convert Gretag/Logo/X-Rite/Barbieri or other format
+ RGB or CMYK test chart results into Argyll .ti3 CGATS format. </big></small><br
+ style="font-family: monospace;">
+ <small><big><small><a style="font-family: monospace;"
+ href="ls2ti3.html">ls2ti3</a><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Convert
@@ -4104,9 +4957,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- LightSpace format RGB .bcs test chart results into Argyll
- .ti3 CGATS format.</big></small></big><br>
- <a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LightSpace format RGB .bcs test chart results into Argyll
+ .ti3 CGATS format.</big></small></big><br>
+ <a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4204,10 +5080,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span><big>Create a fake Argyll .ti3 CMY data file from a CMYK
- profile, as a basis of creating a CMY to CMYK separation<br>
- </big></small><small><a style="font-family: monospace;"
- href="average.html">average</a><span style="font-family:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Create a fake Argyll .ti3 CMY data file from a CMYK
+ profile, as a basis of creating a CMY to CMYK separation<br>
+ </big></small><small><a style="font-family: monospace;"
+ href="average.html">average</a><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Average
@@ -4234,10 +5133,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- or Merge two or more measurement data files, or average patches
- within a single file.</big></small><br>
- <h3>Creating Device Profiles</h3>
- <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ or Merge two or more measurement data files, or average patches
+ within a single file.</big></small><br>
+ <h3>Creating Device Profiles</h3>
+ <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4335,8 +5257,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Create an ICC profile from the .ti3 test data. <br>
- <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create an ICC profile from the .ti3 test data. <br>
+ <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4434,9 +5379,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Create a Model Printer Profile (MPP) from the .ti3
- test data. <br>
- <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create a Model Printer Profile (MPP) from the .ti3
+ test data. <br>
+ <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4534,10 +5502,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Regenerate a device profiles B2A table data by
- inverting the A2B table.
- <h3>Creating Device Link Profiles</h3>
- <small><a style="font-family: monospace;" href="collink.html">collink</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Regenerate a device profiles B2A table data by
+ inverting the A2B table.
+ <h3>Creating Device Link Profiles</h3>
+ <small><a style="font-family: monospace;" href="collink.html">collink</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4635,11 +5626,34 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Link two device ICC profiles to create a device
- link profile.
- <h3>Converting colors or applying print calibration<br>
- </h3>
- <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Link two device ICC profiles to create a device
+ link profile.
+ <h3>Converting colors or applying print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4737,10 +5751,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Color convert a TIFF or JPEG file using a sequence
- of ICC device, device link, abstract profiles and calibration files.
- <br>
- <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Color convert a TIFF or JPEG file using a sequence
+ of ICC device, device link, abstract profiles and calibration files.
+ <br>
+ <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Apply
@@ -4837,8 +5874,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- calibration curves to an ICC profile.<br>
- <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ calibration curves to an ICC profile.<br>
+ <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4936,9 +5996,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Lookup individual color values through any ICC
- profile table. <br>
- <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values through any ICC
+ profile table. <br>
+ <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -5036,9 +6119,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Lookup individual color values forward or inverted
- though an ICC profile or CAL table. <br>
- <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values forward or inverted
+ though an ICC profile or CAL table. <br>
+ <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -5136,9 +6242,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Lookup individual color values though an MPP
- profile. Also create MPP gamut files/views.<br>
- <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values though an MPP
+ profile. Also create MPP gamut files/views.<br>
+ <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
@@ -5236,17 +6365,40 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a TIFF file to monochrome using an ICC device profile <br>
- <h3>Color Tweaking tools<br>
- </h3>
- <small><a style="font-family: monospace;" href="refine.html">refine</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
- abstract profile from two chart readings, useful for refining
- proofing profiles. <a href="mppprof.html"><br>
- </a>
- <h3>Creating gamut views</h3>
- <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a TIFF file to monochrome using an ICC device profile <br>
+ <h3>Color Tweaking tools<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="refine.html">refine</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
+ abstract profile from two chart readings, useful for refining
+ proofing profiles. <a href="mppprof.html"><br>
+ </a>
+ <h3>Creating gamut views</h3>
+ <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -5344,8 +6496,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a gamut file or VRML file of the color gamut of an ICC profile. <br>
- <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a gamut file or VRML file of the color gamut of an ICC profile. <br>
+ <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -5443,9 +6618,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a gamut file or VRML file of the color gamut of a TIFF or JPEG
- image. <br>
- <small><a style="font-family: monospace;" href="viewgam.html">viewgam</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a gamut file or VRML file of the color gamut of a TIFF or JPEG
+ image. <br>
+ <small><a style="font-family: monospace;" href="viewgam.html">viewgam</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -5543,11 +6741,34 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Convert one or more gamuts into a VRML 3D
- visualization file. Compute an intersection.<br>
- <h3>Diagnostic and test tools<br>
- </h3>
- <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Convert one or more gamuts into a VRML 3D
+ visualization file. Compute an intersection.<br>
+ <h3>Diagnostic and test tools<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -5645,8 +6866,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Dump the contents of an ICC profile as text. <br>
- <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Dump the contents of an ICC profile as text. <br>
+ <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
@@ -5744,8 +6988,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an ICC profile against .ti3 test chart data, create pruned .ti3
- file.<br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an ICC profile against .ti3 test chart data, create pruned .ti3
+ file.<br>
<small style="font-family: monospace;"><a href="invprofcheck.html">invprofcheck</a>&nbsp;
@@ -5843,8 +7110,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </small>Check ICC forward against inverse lookup. <br>
- <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </small>Check ICC forward against inverse lookup. <br>
+ <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Split
@@ -5941,12 +7231,35 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a CGATS file (ie. a .ti3) into two parts randomly to verify
- profiling. <br>
- <small style="font-family: monospace;"><a href="timage.html">timage</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Create TIFF test
- images. <br>
- <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a CGATS file (ie. a .ti3) into two parts randomly to verify
+ profiling. <br>
+ <small style="font-family: monospace;"><a href="timage.html">timage</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Create TIFF test
+ images. <br>
+ <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
@@ -6044,8 +7357,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an MPP profile against .ti3 test chart data. <br>
- <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an MPP profile against .ti3 test chart data. <br>
+ <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -6142,8 +7478,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an instrument to read a single spot color value. <br>
- <small><a style="font-family: monospace;" href="colverify.html">colverify</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an instrument to read a single spot color value. <br>
+ <small><a style="font-family: monospace;" href="colverify.html">colverify</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Verify
@@ -6184,9 +7543,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- matching of CIE in two CGATS/.ti3 files (also view differences as
- VRML)<br>
- <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ matching of CIE in two CGATS/.ti3 files (also view differences as
+ VRML)<br>
+ <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -6283,10 +7665,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a synthetic input, display or output calibration (<a
- href="File_Formats.html#.cal">.cal</a>)file.
- <h3>Other Tools</h3>
- <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a synthetic input, display or output calibration (<a
+ href="File_Formats.html#.cal">.cal</a>)file.
+ <h3>Other Tools</h3>
+ <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -6383,12 +7788,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a Spectrometer to create a Colorimeter Correction Matrix
- (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
- for a particular display.<br>
- <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
- style="font-family: monospace;"></span></small><small><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp; </span>Extract
@@ -6411,6 +7810,13 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ a Spectrometer to create a Colorimeter Correction Matrix
+ (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
+ for a particular display.<br>
+ <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; </span>Extract
@@ -6485,15 +7891,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an embedded ICC profile from a TIFF or JPEG file.<br>
- </small><small><a style="font-family: monospace;"
- href="extractttag.html">extractttag</a><span style="font-family:
- monospace;"></span></small><small><span style="font-family:
- monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
- .ti3 data or CAL) from an ICC profile.</small><br>
- <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
- style="font-family: monospace;"></span></small><small><span
- style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; </span></small>Install
@@ -6538,6 +7935,16 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ an embedded ICC profile from a TIFF or JPEG file.<br>
+ </small><small><a style="font-family: monospace;"
+ href="extractttag.html">extractttag</a><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
+ .ti3 data or CAL) from an ICC profile.</small><br>
+ <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; </span></small>Install
@@ -6590,16 +7997,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- or uninstall display profile, set display calibration from profile
- or .cal file, test displace and dispwin access to a display.<br>
- <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- </span></small>Install Instrument manufacturers files for the
- Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4 or
- 5,&nbsp; CCMX files for colorimeters.<br>
- <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
- style="text-decoration: underline; font-family: monospace;"></span></small>&nbsp;
@@ -6666,6 +8063,17 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ or uninstall display profile, set display calibration from profile
+ or .cal file, test displace and dispwin access to a display.<br>
+ <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span></small>Install Instrument manufacturers files for the
+ Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4 or
+ 5,&nbsp; CCMX files for colorimeters.<br>
+ <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
+ style="text-decoration: underline; font-family: monospace;"></span></small>&nbsp;
@@ -6696,10 +8104,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
- <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
- style="text-decoration: underline; font-family: monospace;"></span></small>Convert
@@ -6788,6 +8192,19 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
+ <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
+ style="text-decoration: underline; font-family: monospace;"></span></small>Convert
+
+
+
+
+
+
+
+
@@ -6796,12 +8213,18 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- reflective spectral .ti3 readings into CIE XYZ and D50 L*a*b*
- readings. Apply FWA, plot spectrums.<br>
- &nbsp;
- <h2><b><u><font size="+2"><a name="AlphList"></a>Main Tools
- Alphabetic Listing:</font></u></b></h2>
- <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
+
+
+
+
+
+
+ spectral .ti3 or .sp readings into CIE XYZ and D50 L*a*b* readings.
+ Apply FWA, plot spectrums.<br>
+ &nbsp;
+ <h2><b><u><font size="+2"><a name="AlphList"></a>Main Tools
+ Alphabetic Listing:</font></u></b></h2>
+ <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Apply
@@ -6898,8 +8321,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- calibration curves to an ICC profile.<br>
- <small><a style="font-family: monospace;" href="average.html">average</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ calibration curves to an ICC profile.<br>
+ <small><a style="font-family: monospace;" href="average.html">average</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -6997,9 +8443,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small><small><big>Average or Merge two or more
- measurement data files, or average patches within a single file.</big></small><br>
- <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small><small><big>Average or Merge two or more
+ measurement data files, or average patches within a single file.</big></small><br>
+ <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -7097,9 +8566,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Convert Colorblind format CMY/RGB test chart into
- Argyll .ti3 CGATS format. <br>
- <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Convert Colorblind format CMY/RGB test chart into
+ Argyll .ti3 CGATS format. <br>
+ <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -7197,10 +8689,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Color convert a TIFF or JPEG file using a sequence
- of ICC device, device link, abstract profiles and calibration files.<br>
- <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -7223,6 +8711,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ </span></small>Color convert a TIFF or JPEG file using a sequence
+ of ICC device, device link, abstract profiles and calibration files.<br>
+ <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -7296,11 +8789,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a Spectrometer to create a Colorimeter Correction Matrix
- (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
- for a particular display.<br>
- <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Read
@@ -7345,6 +8833,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ a Spectrometer to create a Colorimeter Correction Matrix
+ (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
+ for a particular display.<br>
+ <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Read
@@ -7397,9 +8891,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a test chart using an instrument to create a .ti3 data file. <br>
- <small><a style="font-family: monospace;" href="collink.html">collink</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -7466,6 +8957,22 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ a test chart using an instrument to create a .ti3 data file. <br>
+ <small><a style="font-family: monospace;" href="collink.html">collink</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
@@ -7496,10 +9003,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Link two device ICC profiles to create a device
- link profile. <br>
- <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -7576,6 +9079,13 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ </span></small>Link two device ICC profiles to create a device
+ link profile. <br>
+ <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
@@ -7596,10 +9106,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Create an ICC profile from the .ti3 test data.<br>
- <font size="-1"><a style="font-family: monospace;"
- href="colverify.html">colverify</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></font>Verify
@@ -7696,12 +9202,16 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- matching of CIE in two CGATS/.ti3 files (also view differences as
- VRML)<br>
- <small style="font-family: monospace;"><a href="dispcal.html">dispcal</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Adjust, calibrate and
- profile a display<small><big>.</big></small><br>
- <small><a style="font-family: monospace;" href="dispread.html">dispread</a><span
+
+ </span></small>Create an ICC profile from the .ti3 test data.<br>
+ <font size="-1"><a style="font-family: monospace;"
+ href="colverify.html">colverify</a><span style="font-family:
+ monospace;"> &nbsp;&nbsp;&nbsp; </span></font>Verify matching
+ of CIE in two CGATS/.ti3 files (also view differences as VRML)<br>
+ <small style="font-family: monospace;"><a href="dispcal.html">dispcal</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Adjust, calibrate and
+ profile a display<small><big>.</big></small><br>
+ <small><a style="font-family: monospace;" href="dispread.html">dispread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Test
@@ -7799,9 +9309,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- and read colorimetric values from a display <br>
- <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
- style="font-family: monospace;"></span></small><small><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and read colorimetric values from a display <br>
+ <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
+ style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; </span></small>Install
@@ -7899,10 +9432,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- or uninstall display profile, set display calibration from profile
- or .cal file, test displace and dispwin access to a display.<br>
- <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
- style="font-family: monospace;"></span></small><small><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ or uninstall display profile, set display calibration from profile
+ or .cal file, test displace and dispwin access to a display.<br>
+ <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
+ style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp; </span>Extract
@@ -8000,13 +9556,36 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an embedded ICC profile from a TIFF or JPEG file.<br>
- </small><small><a style="font-family: monospace;"
- href="extractttag.html">extractttag</a><span style="font-family:
- monospace;"></span></small><small><span style="font-family:
- monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
- .ti3 data or CAL) from an ICC profile.</small><br>
- <small><a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an embedded ICC profile from a TIFF or JPEG file.<br>
+ </small><small><a style="font-family: monospace;"
+ href="extractttag.html">extractttag</a><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
+ .ti3 data or CAL) from an ICC profile.</small><br>
+ <small><a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -8104,9 +9683,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Create a fake Argyll .ti3 CMY data file from a CMYK
- profile, as a basis of creating a CMY to CMYK separation <br>
- <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create a fake Argyll .ti3 CMY data file from a CMYK
+ profile, as a basis of creating a CMY to CMYK separation <br>
+ <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Fake
@@ -8204,8 +9806,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- the reading of a device using an ICC or MPP profile. <br>
- <small><a style="font-family: monospace;" href="filmread.html">filmread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the reading of a device using an ICC or MPP profile. <br>
+ <small><a style="font-family: monospace;" href="filmread.html">filmread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Read
@@ -8303,8 +9928,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- film colorimetric values using a SpectroScanT (Deprecated ?)<br>
- <small><a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ film colorimetric values using a SpectroScanT (Deprecated ?)<br>
+ <small><a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -8402,8 +10050,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- film recorder TIFF files from Argyll .ti1 file. <br>
- <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ film recorder TIFF files from Argyll .ti1 file. <br>
+ <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
@@ -8501,9 +10172,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a TIFF file to monochrome using an ICC device profile <small><a
- style="font-family: monospace;" href="oeminst.html"></a></small><br>
- <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a TIFF file to monochrome using an ICC device profile <small><a
+ style="font-family: monospace;" href="oeminst.html"></a></small><br>
+ <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -8601,8 +10295,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Dump the contents of an ICC profile as text. <br>
- <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Dump the contents of an ICC profile as text. <br>
+ <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -8700,9 +10417,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a gamut file or VRML file of the color gamut of an ICC profile. <br>
- <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -8725,6 +10439,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ a gamut file or VRML file of the color gamut of an ICC profile. <br>
+ <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -8799,10 +10517,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Lookup individual color values through any ICC
- profile table. <br>
- <small><a style="font-family: monospace;" href="illumread.html">illumread</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use
@@ -8847,6 +10561,24 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ </span></small>Lookup individual color values through any ICC
+ profile table. <br>
+ <small><a style="font-family: monospace;" href="illumread.html">illumread</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -8898,13 +10630,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an instrument to measure an illuminant spectrum, and estimate its UV
- content.<br>
- <small><a style="font-family: monospace;" href="invprofcheck.html">invprofcheck</a><span
- style="font-family: monospace;">&nbsp; </span></small>Check ICC
- forward against inverse lookup. <br>
- <small><a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
@@ -8958,6 +10683,14 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ an instrument to measure an illuminant spectrum, and estimate its UV
+ content.<br>
+ <small><a style="font-family: monospace;" href="invprofcheck.html">invprofcheck</a><span
+ style="font-family: monospace;">&nbsp; </span></small>Check ICC
+ forward against inverse lookup. <br>
+ <small><a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
@@ -9001,11 +10734,6 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
- format. <br>
- <small><big><small><a style="font-family: monospace;"
- href="ls2ti3.html">ls2ti3</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9081,6 +10809,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
+
+ Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
+ format. <br>
+ <small><big><small><a style="font-family: monospace;"
+ href="ls2ti3.html">ls2ti3</a><span style="font-family:
+ monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Convert
@@ -9102,9 +10836,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span><big>Convert LightSpace format RGB .bcs test chart
- results into Argyll .ti3 CGATS format.</big></small></big></small><br>
- <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
+
+ LightSpace format RGB .bcs test chart results into Argyll
+ .ti3 CGATS format.</big></small></big></small><br>
+ <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
@@ -9202,8 +10937,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an MPP profile against .ti3 test chart data. <br>
- <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an MPP profile against .ti3 test chart data. <br>
+ <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9301,9 +11059,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Lookup individual color values though an MPP
- profile. Also create MPP gamut files/views. <br>
- <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values though an MPP
+ profile. Also create MPP gamut files/views. <br>
+ <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9401,14 +11182,37 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Create a Model Printer Profile (MPP) from the .ti3
- test data. <br>
- <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- </span></small>Install Instrument manufacturers files for the
- Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4 or
- 5,&nbsp; CCMX files for colorimeters.<br>
- <small><a style="font-family: monospace;" href="printcal.html">printcal</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create a Model Printer Profile (MPP) from the .ti3
+ test data. <br>
+ <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span></small>Install Instrument manufacturers files for the
+ Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4 or
+ 5,&nbsp; CCMX files for colorimeters.<br>
+ <small><a style="font-family: monospace;" href="printcal.html">printcal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -9505,8 +11309,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
- <small><a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
+ <small><a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small><small><big>Create
@@ -9604,9 +11431,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a PS, EPS or TIFF file containing test patch values, ready for
- printing.</big></small><br>
- <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a PS, EPS or TIFF file containing test patch values, ready for
+ printing.</big></small><br>
+ <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
@@ -9704,14 +11554,37 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an ICC profile against .ti3 test chart data, create pruned .ti3
- file.<br>
- <small><a style="font-family: monospace;" href="refine.html">refine</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
- abstract profile from two chart readings, useful for refining
- proofing profiles. <br>
- <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an ICC profile against .ti3 test chart data, create pruned .ti3
+ file.<br>
+ <small><a style="font-family: monospace;" href="refine.html">refine</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
+ abstract profile from two chart readings, useful for refining
+ proofing profiles. <br>
+ <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9809,9 +11682,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Regenerate a device profiles B2A table data by
- inverting the A2B table. <br>
- <small><a style="font-family: monospace;" href="scanin.html">scanin</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Regenerate a device profiles B2A table data by
+ inverting the A2B table. <br>
+ <small><a style="font-family: monospace;" href="scanin.html">scanin</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9909,10 +11805,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Convert a TIFF&nbsp; image of a test chart into
- .ti3 device values. <br>
- <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Convert a TIFF&nbsp; image of a test chart into
+ .ti3 device values. <br>
+ <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
style="text-decoration: underline; font-family: monospace;"></span></small>Convert
@@ -10010,10 +11929,33 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- reflective spectral .ti3 readings into CIE XYZ and D50 L*a*b*
- readings. Apply FWA, plot spectrums.<br>
- <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ spectral .ti3 or .sp readings into CIE XYZ and D50 L*a*b* readings.
+ Apply FWA, plot spectrums.<br>
+ <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
style="text-decoration: underline; font-family: monospace;"></span></small>&nbsp;
@@ -10111,8 +12053,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
- <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
+ <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Split
@@ -10209,9 +12174,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a CGATS file (ie. a .ti3) into two parts randomly to verify
- profiling. <br>
- <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a CGATS file (ie. a .ti3) into two parts randomly to verify
+ profiling. <br>
+ <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -10308,9 +12296,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- an instrument to read a single spot color value. <small><a
- style="font-family: monospace;" href="oeminst.html"></a></small><br>
- <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an instrument to read a single spot color value. <small><a
+ style="font-family: monospace;" href="oeminst.html"></a></small><br>
+ <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -10407,9 +12418,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a synthetic input, display or output calibration (<a
- href="File_Formats.html#.cal">.cal</a>)file.<br>
- <small><a style="font-family: monospace;" href="synthread.html">synthread</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a synthetic input, display or output calibration (<a
+ href="File_Formats.html#.cal">.cal</a>)file.<br>
+ <small><a style="font-family: monospace;" href="synthread.html">synthread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake
@@ -10507,8 +12541,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- the reading of a device using a synthetic device model. </big></small><br>
- <small><a style="font-family: monospace;" href="targen.html">targen</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the reading of a device using a synthetic device model. </big></small><br>
+ <small><a style="font-family: monospace;" href="targen.html">targen</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -10606,9 +12663,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Generate a profiling test target values .ti1 file.
- <br>
- <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Generate a profiling test target values .ti1 file.
+ <br>
+ <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -10706,13 +12786,36 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- a gamut file or VRML file of the color gamut of a TIFF or JPEG
- image. <br>
- <small><a style="font-family: monospace;" href="timage.html">timage</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create TIFF
- test images. <br>
- <small><a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a gamut file or VRML file of the color gamut of a TIFF or JPEG
+ image. <br>
+ <small><a style="font-family: monospace;" href="timage.html">timage</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create TIFF
+ test images. <br>
+ <small><a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -10810,11 +12913,34 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small><small><big>Convert Gretag/Logo/X-Rite/Barbieri or
- other format RGB or CMYK test chart results into Argyll .ti3
- CGATS format.</big></small> <br>
- <font size="-1"><a style="font-family: monospace;"
- href="viewgam.html">viewgam</a><span style="font-family:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small><small><big>Convert Gretag/Logo/X-Rite/Barbieri or
+ other format RGB or CMYK test chart results into Argyll .ti3
+ CGATS format.</big></small> <br>
+ <font size="-1"><a style="font-family: monospace;"
+ href="viewgam.html">viewgam</a><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font>Convert
@@ -10911,9 +13037,32 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- one or more gamuts into a VRML 3D visualization file. Compute an
- intersection.<br>
- <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ one or more gamuts into a VRML 3D visualization file. Compute an
+ intersection.<br>
+ <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11011,36 +13160,59 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- </span></small>Lookup individual color values forward or inverted
- though an ICC profile or CAL table. <br>
- <br>
- <h2><u><a href="Environment.html">Environment Variables<br>
- </a></u></h2>
- <span style="text-decoration: underline;"><span style="font-weight:
- bold;"></span></span> Performance/memory tuning hints, plus
- tweaks for scipting.<br>
- <h2><u><a href="Performance.html">Performance Tuning<br>
- </a></u></h2>
- <span style="text-decoration: underline;"><span style="font-weight:
- bold;"></span></span> Performance hints. <br>
- <h2><u><a href="Overview.html">Overview</a></u></h2>
- Overview of the software and its aims and functionality.<br>
- <h2><u><a href="Limitations.html">Limitations</a></u></h2>
- Limitations of the current functionality.<br>
- <h2><u><a href="Organisation.html">Organization</a></u></h2>
- How directories are organized, what they contain.
- <h2><u><a href="Source.html">Source</a></u></h2>
- Any detailed documentation on how the software works, or what
- algorithms it is based on. (Very incomplete.)
- <h2><u><a href="MinorTools.html">Minor Tools</a></u></h2>
- A very brief description of minor tools and test harnesses. <br>
- <br>
- <br>
- <h2><u><a name="FFormats"></a><a href="File_Formats.html">File
- formats that Argyll uses</a></u></h2>
- Argyll uses a number of file formats for its operation, some that
- are external standards, and some that are unique to Argyll. <br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values forward or inverted
+ though an ICC profile or CAL table. <br>
+ <br>
+ <h2><u><a href="Environment.html">Environment Variables<br>
+ </a></u></h2>
+ <span style="text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span> Performance/memory tuning hints, tweaks
+ for srcipting, plus lesser used behavior options.<br>
+ <h2><u><a href="Performance.html">Performance Tuning<br>
+ </a></u></h2>
+ <span style="text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span> Performance hints. <br>
+ <h2><u><a href="Overview.html">Overview</a></u></h2>
+ Overview of the software and its aims and functionality.<br>
+ <h2><u><a href="Limitations.html">Limitations</a></u></h2>
+ Limitations of the current functionality.<br>
+ <h2><u><a href="Organisation.html">Organization</a></u></h2>
+ How directories are organized, what they contain.
+ <h2><u><a href="Source.html">Source</a></u></h2>
+ Any detailed documentation on how the software works, or what
+ algorithms it is based on. (Very incomplete.)
+ <h2><u><a href="MinorTools.html">Minor Tools</a></u></h2>
+ A very brief description of minor tools and test harnesses. <br>
+ <br>
+ <br>
+ <h2><u><a name="FFormats"></a><a href="File_Formats.html">File
+ formats that Argyll uses</a></u></h2>
+ Argyll uses a number of file formats for its operation, some that
+ are external standards, and some that are unique to Argyll. <br>
+ <br>
<a href="File_Formats.html#.ti1">.ti1</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11138,7 +13310,30 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Device test values <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Device test values <br>
<a href="File_Formats.html#.ti2">.ti2</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11236,7 +13431,30 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Device test values &amp; chart layout <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Device test values &amp; chart layout <br>
<a href="File_Formats.html#.ti3">.ti3</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11334,11 +13552,34 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Device test values &amp; CIE tristimulus/spectral results&nbsp; <a
- href="ti3_format.html">Format details.</a><br>
- <a href="File_Formats.html#.cal">.cal</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Device
- calibration information. <a href="cal_format.html">Format details.</a><br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Device test values &amp; CIE tristimulus/spectral results&nbsp; <a
+ href="ti3_format.html">Format details.</a><br>
+ <a href="File_Formats.html#.cal">.cal</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Device
+ calibration information. <a href="cal_format.html">Format details.</a><br>
<a href="File_Formats.html#.cht">.cht</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11436,8 +13677,31 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Test chart recognition template. <a href="cht_format.html">Format
- details.</a> <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Test chart recognition template. <a href="cht_format.html">Format
+ details.</a> <br>
<a href="File_Formats.html#.gam">.gam</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11535,7 +13799,30 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- 3D gamut surface description <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3D gamut surface description <br>
<a href="File_Formats.html#.sp">.sp</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11633,15 +13920,38 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Illuminant spectral description <br>
- <a href="File_Formats.html#.cmf">.cmf</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Color Matching
- Functions<br>
- <a href="File_Formats.html#.ccmx">.ccmx</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Colorimeter Correction Matrix <br>
- <a href="File_Formats.html#.ccmx">.ccss</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Colorimeter Calibration
- Spectral Set <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Illuminant spectral description <br>
+ <a href="File_Formats.html#.cmf">.cmf</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Color Matching
+ Functions<br>
+ <a href="File_Formats.html#.ccmx">.ccmx</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Colorimeter Correction Matrix <br>
+ <a href="File_Formats.html#.ccmx">.ccss</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Colorimeter Calibration
+ Spectral Set <br>
<a href="File_Formats.html#CGATS">CGATS</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11739,7 +14049,30 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Standard text based data exchange format <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Standard text based data exchange format <br>
<a href="File_Formats.html#ICC">ICC</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11837,7 +14170,30 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- International Color Consortium profile format <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ International Color Consortium profile format <br>
<a href="File_Formats.html#MPP">MPP</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11935,7 +14291,30 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Model device profile format <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Model device profile format <br>
<a href="File_Formats.html#TIFF">TIFF</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -12033,7 +14412,30 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Tag Image File Format raster files. <br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tag Image File Format raster files. <br>
<a href="File_Formats.html#JPEG">JPEG</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -12131,12 +14533,35 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Joint Photographic Experts Group, JPEG File Interchange Format
- raster files. <br>
- <a href="doc/ucmm.html">ucmm</a> &nbsp;
- &nbsp;&nbsp;&nbsp; Unix micro Color Management Module convention and
- configuration file format and <span style="color: rgb(204, 0, 0);
- font-weight: bold;">Profile Locations</span>.<br>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Joint Photographic Experts Group, JPEG File Interchange Format
+ raster files. <br>
+ <a href="ucmm.html">ucmm</a> &nbsp; &nbsp;&nbsp;&nbsp; Unix micro
+ Color Management Module convention and configuration file format and
+ <span style="color: rgb(204, 0, 0); font-weight: bold;">Profile
+ Locations</span>.<br>
<a href="File_Formats.html#VRML">VRML</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -12234,42 +14659,65 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
- Virtual Reality Modelling Language 3D file format. <br>
- <a href="File_Formats.html#X3D">X3D</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open
- standards file format to represent 3D scenes using XML.<br>
- <a href="File_Formats.html#X3DOM">X3DOM</a> &nbsp;&nbsp;&nbsp;
- Open-source framework and runtime for 3D graphics on the Web.<br>
- <br>
- &nbsp;
- <h2><u>Errors, Corrections and Omissions:</u></h2>
- <script language="JavaScript">
-<!--
-// Comment
-var v1 = ".com"
-var v2 = "argyllcms"
-var v3 = "Graeme"
-var v4 = "@"
-var v5 = "mailto:"
-var v6 = v5 + v3 + v4 + v2 + v1
-document.write("<a href=" + v6 + ">" + "Let me know" + "</a>")
-//-->
-</script> If you notice any errors, corrections needed or omissions in
- the current documentation, please contact the author.<br>
- &nbsp; <br>
- &nbsp;<br>
- </body>
-</html>
+
+
+
+
+
+
+
+
+
+
+ Virtual Reality Modelling Language 3D file format. <br>
+ <a href="File_Formats.html#X3D">X3D</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open
+ standards file format to represent 3D scenes using XML.<br>
+ <a href="File_Formats.html#X3DOM">X3DOM</a> &nbsp;&nbsp;&nbsp;
+ Open-source framework and runtime for 3D graphics on the Web.<br>
+ <br>
+ &nbsp;
+ <h2><u>Errors, Corrections and Omissions:</u></h2>
+ <script language="JavaScript">
+
+<!--
+
+// Comment
+
+var v1 = ".com"
+
+var v2 = "argyllcms"
+
+var v3 = "Graeme"
+
+var v4 = "@"
+
+var v5 = "mailto:"
+
+var v6 = v5 + v3 + v4 + v2 + v1
+
+document.write("<a href=" + v6 + ">" + "Let me know" + "</a>")
+
+//-->
+
+
+
+</script> If you notice any errors, corrections needed or omissions in
+ the current documentation, please contact the author.<br>
+ &nbsp; <br>
+ &nbsp;<br>
+ </body>
+</html>
diff --git a/doc/CMP_Digital_Target-7.jpg b/doc/CMP_Digital_Target-7.jpg
new file mode 100644
index 0000000..b5eaab6
--- /dev/null
+++ b/doc/CMP_Digital_Target-7.jpg
Binary files differ
diff --git a/doc/ChangesSummary.html b/doc/ChangesSummary.html
index fb586e3..459285f 100644
--- a/doc/ChangesSummary.html
+++ b/doc/ChangesSummary.html
@@ -16,6 +16,74 @@
<h1> Summary of Argyll CMS Changes since last release</h1>
<h3>For a <span style="text-decoration: underline;">complete</span>
and more detailed list of changes, please see the log.txt file.</h3>
+ <h1>[V1.8.3 -&gt; V1.9.1] 28th September 2016</h1>
+ <ul>
+ <li>Improved robustness of ChromeCast discovery, and added some
+ minimal diagnostics.<br>
+ </li>
+ <li>Improved robustness of targen ofps patch generation when using
+ less well behaved pre-conditioning profiles.<br>
+ </li>
+ <li>Fixed oeminst so that it locates cdrom's in Linuxes latest
+ mount point of /run/media/$USER/.<br>
+ </li>
+ <li>Fixed bug in i1pro2 driver, in which strip calibration would
+ fail if instrument had been first calibrated with
+ ARGYLL_DISABLE_I1PRO2_DRIVER set, and then calibrated with
+ ARGYLL_DISABLE_I1PRO2_DRIVER unset.<br>
+ </li>
+ <li>Added option to icclib to write Output profiles using 'chad'
+ tag if the ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD&nbsp;
+ environment variable is set. This is not recommended for normal
+ use, but may assist compatibility with other systems.</li>
+ <li>Added JETI spectraval support, including Bluetooth access.</li>
+ <li>Added support for the Klein K10 connecting via a serial port.</li>
+ <li>Fixed bug in Colormunki Smile driver that causes crash on
+ Ubuntu 16.04.1 LTS.</li>
+ <li>Modified "lp" intent to greatly reduce eliminate
+ Helmholtz-Kohlrausch appearance modelling.<br>
+ </li>
+ <li>Fixed problem with targen -g, in that the corresponding XYZ
+ values had double the power applied, rather than none. This was
+ causing problems with printtarg spacer colors.<br>
+ </li>
+ <li>Extensive re-write of colorimetric nearest clipping code in
+ rspl/rev.c to restore precision that was lost in the speedups
+ made in V1.0.0. The nnrev setup now takes a lot longer with
+ &nbsp; high resolution CMYK profiles though. This corrects a
+ "green becoming too yellow" problem for mapping from ProPhoto
+ space with some RGB devices.</li>
+ <li>Change dispwin to properly set X11 DirectColor and take
+ account of TrueColor Colormap.&nbsp; This fixes problem with
+ NVidia linux driver 364.12 exposing a VideoLUT depth that is
+ different from the frame buffer depth.</li>
+ <li>Change icclib to automatically repair icmTextDescription
+ strings that have an allocation that is longer than their size.</li>
+ <li>Added i1Pro Lamp Drift test and fix functions to spotread (-Y
+ l|L options).</li>
+ <li>Change colprof so that -s -S will accept general compression
+ percentage as an alternative to a source colorspace/image gamut.</li>
+ <li>Added optional conversion from native Gretag-MacBeth &amp;
+ X-Rite reflective calibration standards to/from XRGA.</li>
+ <li>Changed OS X GUI support code so as not to switch to "interact
+ with the Dock" mode until actual GUI element is to be displayed.
+ This prevents batch commands with optional GUI elements from
+ blocking normal GUI interactions.</li>
+ <li>Re-jigged OS X UI code to use the main thread to avoid window
+ creation timing issues and a warning backtrace on OS X 10.11.</li>
+ <li>Added CMP_Digital_Target-7.cht</li>
+ <li>Fix spec2cie to cope with .ti3 files that are missing device
+ values, so that it can process a wider range of input CIE
+ reference files.</li>
+ <li>Changed implementation of ARGYLL_NOT_INTERACTIVE on MSWin to
+ make it more reliable when operated progromatically.</li>
+ <li>Fixed chartread so that if you are reading patch by patch, the
+ location strings can be arbitrary (i.e. they don't have to
+ conform to an alpha/num strip/patch pattern.)</li>
+ <li>Added support for Sencore ColorPro V, IV &amp; III
+ colorimeters (based on Sequel Chroma colorimeter.).<br>
+ </li>
+ </ul>
<h1>[V1.8.2 -&gt; V1.8.3] 26th October 2015</h1>
<ul>
<li>Added SpyderCheckr24 scaning .cht and .cie files.</li>
@@ -1031,6 +1099,17 @@
+
+
+
+
+
+
+
+
+
+
+
</span>for systems with &gt; 3Gig Ram.</li>
<li>Add support for the Eye-One Monitor spectrometer.</li>
<li>Added -L option to <span style="font-weight: bold;">printtarg</span>
@@ -1072,6 +1151,17 @@
+
+
+
+
+
+
+
+
+
+
+
and memory usage issues.</li>
<li>Fixed issues with Eye-One Pro Rev B timeouts.</li>
<li>Added new option to collink -fk, that forces 000K input to K
diff --git a/doc/Environment.html b/doc/Environment.html
index b4cd9ca..c4c1aed 100644
--- a/doc/Environment.html
+++ b/doc/Environment.html
@@ -10,9 +10,53 @@
<title>Argyll Environment Variables</title>
</head>
<body>
+ <h2><u>Setting an environment variable</u></h2>
+ &nbsp;To set an environment variable an MSWindows DOS shell, either
+ use set, e.g.;<br>
<br>
- <h2> <u>Environment variables<br>
- </u></h2>
+ &nbsp;&nbsp;&nbsp; set ARGYLL_REV_CACHE_MULT=1.5<br>
+ <br>
+ which will set the value for that session, or set it in<br>
+ <br>
+ Control Panel-&gt;System-&gt;Advanced-&gt;Environment Variables..<br>
+ <br>
+ in either user or system variables.<br>
+ <br>
+ You can examine individual variables using<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; echo %VARIABLE_NAME%<br>
+ <br>
+ or see all of them using<br>
+ <br>
+ &nbsp;&nbsp; set<br>
+ <br>
+ <br>
+ For OS X or Linux, the exact procedure will depend on the shell you
+ are running, but<br>
+ is usually something like:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; export ARGYLL_REV_CACHE_MULT=1.5<br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; set ARGYLL_REV_CACHE_MULT=1.5<br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; ARGYLL_REV_CACHE_MULT=1.5<br>
+ <br>
+ and may need separately exporting, something like:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; export ARGYLL_REV_CACHE_MULT<br>
+ <br>
+ Generally it should be configured in the shell start-up
+ script,&nbsp; if you want the setting to be used<br>
+ for every session.<br>
+ <br>
+ You can examine individual variables using<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; echo $VARIABLE_NAME<br>
+ <br>
+ or see all of them using<br>
+ <br>
+ &nbsp;&nbsp; set<br>
+ <h2><u>Environment variables</u></h2>
The following environment variables affect behaviour:<br>
<br>
<span style="font-weight: bold;"><a name="ARGYLL_NOT_INTERACTIVE"></a>ARGYLL_NOT_INTERACTIVE</span><br>
@@ -45,6 +89,14 @@
&nbsp;&nbsp;&nbsp; Note that on MSWin systems, the character and
return or line fee characters must be written to stdin in a single
operation (i.e. testing <span style="font-weight: bold;">ARGYLL_NOT_INTERACTIVE&nbsp;
+
+
+
+
+
+
+
+
</span>mode manually will probably fail, because the character and
return get split up.)<br>
</div>
@@ -58,12 +110,28 @@
+
+
+
+
+
+
+
+
</b>or <b>X3DOM</b>, which will result in <b>.wrl</b>, <b>.x3d</b>
and <b>.x3d.html</b> files respectively. See <a href="3dformat">3d
+
+
+
+
+
+
+
+
Viewing Format</a>.<br>
</blockquote>
<b><br>
@@ -97,6 +165,14 @@ a
+
+
+
+
+
+
+
+
delay of 200 msec is allowed between changing a patch color in
software, and that change appearing in the displayed color itself.
For some instuments (ie. i1d3, i1pro, ColorMunki, Klein K10-A)
@@ -116,6 +192,14 @@ environment
+
+
+
+
+
+
+
+
variable, ie. ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS=400 would set a
400 msec minimum delay.<br>
<span style="font-weight: bold;"><br>
@@ -158,19 +242,19 @@ environment
as being recommended practice in modelling chromatic
adaption.&nbsp; The ICC profile format though, specifies the use
of a non-cone space XYZ adaptation (so called "Wrong Von Kries"
- chromatic adaptation) [ ICC Specification<br>
- ICC.1:2001-04 (ICCV2.4) Annex A, pp 66, equations A.1, A.2 &amp;
- A.3 ], so ArgyllCMS profiles have a very slight incompatibility
- with ICC profiles created strictly according to the ICC
- specifications, depending on how close to white Output (i.e.
- print) profiles media white is to the perfect diffuser. (Note that
- CMM's that strictly follow the ICC specifications have much more
- gross incompatibilities due to this, when dealing with the HP
- &amp; Microsoft sRGB and AdobeRGB profiles.) By setting this
- environment variable, Output (i.e. print) profiles will be created
- that better conform to the ICC specification, and&nbsp; therefore
- have better inter-interoperability with some other CMMs, at the
- cost of poorer color behavior.<br>
+ chromatic adaptation) [ ICC Specification ICC.1:2001-04 (ICCV2.4)
+ Annex A, pp 66, equations A.1, A.2 &amp; A.3 ], so ArgyllCMS
+ profiles have a very slight incompatibility with ICC profiles
+ created strictly according to the ICC specifications, depending on
+ how close to white Output (i.e. print) profiles media white is to
+ the perfect diffuser. (Note that CMM's that strictly follow the
+ ICC specifications have much more gross incompatibilities due to
+ this, when dealing with the HP &amp; Microsoft sRGB and AdobeRGB
+ profiles.) By setting this environment variable, Output (i.e.
+ print) profiles will be created that better conform to the ICC
+ specification, and&nbsp; therefore have better
+ inter-interoperability with some other CMMs, at the cost of poorer
+ color behavior.<br>
See also the <a href="ArgyllCMS_arts_tag.html">ArgyllCMS 'arts'
tag</a>.<br>
<span style="font-weight: bold;"><span style="font-weight: bold;"><span
@@ -199,7 +283,7 @@ environment
later on with the introduction of the ChromaticAdapation ('chad')
tag, but this did not restore the Absolute Colorimetric capability
to Display profiles. The latter approach has also been adopted
- more formally in the ICC V4 specifications. To improve restore the
+ more formally in the ICC V4 specifications. To restore the
Absolute Intent for such profiles, ArgyllCMS will make use of the
'chad' tag in such profiles when Absolute Colorimetric intent is
requested, but by default does not create such profiles. Setting
@@ -209,8 +293,117 @@ environment
D50 matrix in the 'chad' tag. (This approach has slightly poorer
accuracy for Absolute Intent than ArgyllCMS's default.) <br>
</blockquote>
+ <br>
<span style="font-weight: bold;"><span style="font-weight: bold;"><span
- style="font-weight: bold;"><a
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><a
+ name="ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD"></a>ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD<br>
+ </span></span></span></span></span></span></span></span></span></span></span></span>
+ <blockquote>For Output type devices (i.e. Printers), the assumption
+ is that test patches are measured under D50 illuminant. It can be
+ very useful for proofing to calculate color corrections for other,
+ real world illuminants, and ArgyllCMS makes provision for this
+ with the <a href="colprof.html#i">coloprof -i</a> parameter, or
+ the <a href="spec2cie.html#i">spec2cie -i</a> parameter. To be
+ broadly useful, this change in illuminant needs to be available to
+ CMM's, which the ArgyllCMS's implementation makes possible by
+ incorporating the illuminant change into the absolute XYZ values
+ and hence the white point tag, so that Absolute Colorimetric
+ rendering intent returns XYZ values under that illuminant using
+ any CMM.<br>
+ <br>
+ The ICC specification have provision for hiding this difference in
+ illuminant by chromatically transforming the absolute values to be
+ functionally equivalent to having been measured using a D50
+ illuminant, and recording this transform in the ChromaticAdapation
+ ('chad') tag. This appears to motivated by the assumption that the
+ difference in illuminant is a quirk or limitation of the
+ instrument that is to be worked around, as well as the limitation
+ of the ICC Absolute to Relative chromatic transformation being
+ based on the inferior non-cone space XYZ adaptation (so called
+ "Wrong Von Kries" chromatic adaptation), while the
+ ChromaticAdapation tag allows for the use of a superior cone-space
+ based transformation. (see <span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;">ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP</span></span></span></span></span></span></span></span></span></span></span></span><span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"> </span></span></span></span></span></span></span></span></span></span></span></span>above
+ for more details.)<span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"> <br>
+ <br>
+ </span></span></span></span></span></span></span></span></span></span></span></span>To
+ allow for strict conformance to the ICC specification when using
+ non-standard illuminants, setting the <span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;">ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD
+ </span></span></span></span></span></span></span></span></span></span></span></span>environment
+ variable causes a non-D50 illuminant white point change to be
+ hidden in the ChromaticAdapation Tag, and to still allow this to
+ be useful in a proofing situation, ArgyllCMS will incorporate the
+ effect of the ChromaticAdapation Tag when Absolute Colorimetric
+ Intent is chosen. Note that other CMM's may not do. For full
+ conformance with ICC specifications, the <span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;">ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP</span></span></span></span></span></span></span></span></span></span></span></span>
+ variable would also be set, but neither of these options is
+ recommended, since ArgyllCMS's default behavior will give superior
+ results.<span style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"><br>
+ </span></span></span></span></span></span></span></span></span></span></span></span></blockquote>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span
+ style="font-weight: bold;"></span></span></span></span></span></span></span></span></span><a
name="ARGYLL_CCAST_DEFAULT_RECEIVER"></a>ARGYLL_CCAST_DEFAULT_RECEIVER<br>
</span></span></span>
<blockquote>By default the ChromeCast test patch source uses a
@@ -236,12 +429,27 @@ environment
name="ARGYLL_DISABLE_I1PRO2_DRIVER"></a>ARGYLL_DISABLE_I1PRO2_DRIVER<br>
<br>
</span>
- <div style="margin-left: 40px;">There is now support for most of the
- the Eye-One Pro Rev E (aka Eye-One Pro 2) instrument features, but
- a Rev E can be operated in legacy mode if the environment variable
+ <div style="margin-left: 40px;">ArgyllCMS supports most of the the
+ Eye-One Pro Rev E (aka Eye-One Pro 2) instrument features, but a
+ Rev E can be operated in legacy mode if the environment variable
ARGYLL_DISABLE_I1PRO2_DRIVER is set (ie. set it to "yes").<br>
+ <br>
</div>
- <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"></span><span style="font-weight:
+ bold;"><a name="ARGYLL_XRGA"></a>ARGYLL_XRGA</span><br>
+ <blockquote>If the <span style="font-weight: bold;">ARGYLL_XRGA&nbsp;</span>
+ environment variable is set to:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <b>XRGA</b>, then all Getag-MacBeth/X-Rite
+ reflective measurements will be converted to XRGA.<br>
+ <b>&nbsp;&nbsp;&nbsp; XRDI</b>, then all Getag-MacBeth/X-Rite
+ reflective measurements will be converted to XRDI.<br>
+ <b>&nbsp;&nbsp;&nbsp; GMDI</b>, then all Getag-MacBeth/X-Rite
+ reflective measurements will be converted to GMDI.<br>
+ <br>
+ If not set (or set to some other string), then the native
+ calibration will be used. Note that the values must be upper case.<br>
+ </blockquote>
<span style="font-weight: bold;"><a name="XDG_CACHE_HOME"></a>XDG_CACHE_HOME<br>
<span style="font-weight: bold;"><br>
</span></span>
@@ -257,6 +465,14 @@ Base
+
+
+
+
+
+
+
+
Directory Specification</a>, and uses the <span
style="font-weight: bold;">XDG_CACHE_HOME</span> environment
variable to place per instrument calibration information, and
diff --git a/doc/FWA.html b/doc/FWA.html
index c6b1f4b..e83a64f 100644
--- a/doc/FWA.html
+++ b/doc/FWA.html
@@ -225,9 +225,10 @@
instruments provide an illuminant measurement capability over the
visible spectrum, for FWA compensation it is desirable to know the
Ultra Violet (UV) component of the illuminant. Few color instruments
- are capable of reading to such short wavelengths though. Argyll
- provides an indirect way of estimating the UV component of an
- illuminant using its <a href="illumread.html">illumread</a>
+ are capable of reading to such short wavelengths though (the <a
+ href="instruments.html#specbos">JETI specbos 1211</a> is an
+ exception). Argyll provides an indirect way of estimating the UV
+ component of an illuminant using its <a href="illumread.html">illumread</a>
utility. Using illumread in combination with FWA compensation is the
recommended approach to modelling real world appearance of paper
containing FWA.<br>
diff --git a/doc/File_Formats.html b/doc/File_Formats.html
index ae59dd2..aeddc6d 100644
--- a/doc/File_Formats.html
+++ b/doc/File_Formats.html
@@ -200,7 +200,7 @@
To check if your browser supports X3DOM, try <a
href="http://www.x3dom.org/check/">this test page</a>.<br>
For more information about ArgyllCMS use of it, see <a
- href="3Dformat.html">3D Viewing Format</a>.<br>
+ href="3dformat.html">3D Viewing Format</a>.<br>
<br>
<br>
<br>
diff --git a/doc/Installing_Linux.html b/doc/Installing_Linux.html
index a26d64c..87d7fba 100644
--- a/doc/Installing_Linux.html
+++ b/doc/Installing_Linux.html
@@ -51,6 +51,8 @@
+
+
the <span style="font-weight: bold;">/etc/rc.local</span> startup
script. You may also have to run <span style="font-weight: bold;">xset
@@ -63,6 +65,8 @@
+
+
b 100 1000 100</span> in your local setup, if you are running in
an X11 environment. You can check that the system bell is operating
by doing an "echo ^G", where ^G is ctrl-G.<br>
@@ -181,17 +185,16 @@
/etc/udev/rules.d/55-Argyll.rules file, but for older systems you
probably need to disable libmtp (look in the udev configuration).<br>
<br>
- The <b>JETI</b> specbos <span style="font-weight: bold;">1211</span><span
- style="font-weight: bold;"> </span>and <b>1201</b>, and the <b>Klien
-
-
-
-
- K10A</b> makes use of the <a
+ The <b>JETI</b> specbos <b>1211</b><b>,&nbsp;</b><b>1201</b><b>,
+ 1511, 1501</b> and the <b>Klien K10A</b> makes use of the <a
href="http://www.ftdichip.com/Drivers/VCP.htm">FTDI Virtual COM
Port Drivers</a> (VCP), that should come with any recent version
- of Linux. You may have to add yourself to the <b>dialout</b> group
- to be able to open the instrument.<br>
+ of Linux. Older versions of Linux may not support the FTDI FT231XS
+ chip that the <b>JETI</b> specbos <b>1511, 1501</b> use. You may
+ have to add yourself to the<span style="font-weight: bold;">
+ tty,&nbsp;</span><span style="font-weight: bold;">uucp</span>
+ or&nbsp;<b>dialout</b> group to have permission to open the
+ instrument.<br>
<br>
<span style="font-weight: bold;"></span>
<hr style="width: 100%; height: 2px;">
@@ -255,6 +258,8 @@
+
+
</span>(as appropriate) with&nbsp;owner root, group root,
permissions 644.<br>
<br>
@@ -279,6 +284,8 @@
+
+
<b>/sbin/udevcontrol reload_rules</b> or&nbsp; <span
style="font-weight: bold;">/sbin/udevstart</span> or reboot to get
the new file noticed.<br>
@@ -347,6 +354,8 @@ instruments
+
+
access using hotplug:<br>
</span></h5>
Under <span style="font-weight: bold;">much older versions of Linux</span>,
@@ -395,7 +404,8 @@ instruments
&nbsp;If this doesn't work you will have to run "id yourusername" to
list the current suplemental<br>
&nbsp;groups, and add colord using just "usermod -G
- group1,group2,... yourusername")<br>
+ group1,group2,... yourusername"<br>
+ &nbsp;Another option may be to use gpasswd -a $USER colord))<br>
<br>
You may find that the <span style="font-weight: bold;">colord</span>
group doesn't exist on your system, and if so you will need to
@@ -403,10 +413,10 @@ instruments
<br>
&nbsp; sudo groupadd -r colord<br>
<br>
- and then add youself to the colord group.<br>
+ and then add yourself to the colord group.<br>
<br>
You may have to log out and then in again for the groups to become
- effecive.<br>
+ effective.<br>
<br>
You can test whether your instrument is accessible by plugging it in
and then running "spotread -?" and looking for it listed after the <span
@@ -425,35 +435,42 @@ instruments
+
+
access:</span><br>
</h5>
If you have a serial instrument then you may find that by default
you don't have permission to access the serial ports or a Serial to
USB adapter. Most systems make the serial ports available to any
- user in the <span style="font-weight: bold;">tty</span> and <span
- style="font-weight: bold;">uucp </span>group, so the best way of
- getting access to the serial ports is to add yourself to those
- groups. You can do this either by using a "Users and Groups" system
- administration tool, or on the command line using "usermod":<br>
+ user in the <span style="font-weight: bold;">tty</span>, <span
+ style="font-weight: bold;">uucp </span>or <b>dialout </b>group,
+ so the best way of getting access to the serial ports is to add
+ yourself to the correct group. (You can identify the correct group
+ by looking at the group name shown by <b>ls -l /dev/ttyS*</b> )<b><br>
+ <br>
+ </b>&nbsp;You can add yourself to a group either by using a "Users
+ and Groups" system administration tool, or on the command line using
+ "usermod":<br>
<br>
&nbsp;&nbsp;&nbsp; su root<br>
- &nbsp;&nbsp;&nbsp; usermod -a -G tty,uucp $USER<br>
+ &nbsp;&nbsp;&nbsp; usermod -a -G dialout $USER<br>
<br>
or<br>
<br>
- &nbsp;&nbsp; sudo usermod -a -G tty,uucp $USER<br>
+ &nbsp;&nbsp; sudo usermod -a -G dialout $USER<br>
<br>
(If the usermod program isn't found as root, it might be in
/usr/sbin, ie. use /usr/sbin/usermod .... etc.<br>
&nbsp;If usermod doesn't recognize the -a flag try "usermod -A
- colord $USER".<br>
+ dialout $USER".<br>
&nbsp;If this doesn't work you will have to run "id yourusername" to
list the current suplemental<br>
- &nbsp;groups, and add a tty or uucp group using just "usermod -G
- group1,group2,... yourusername")<br>
+ &nbsp;groups, and add a tty, uucp or dialout group using just
+ "usermod -G group1,group2,... yourusername"<br>
+ &nbsp;Another option may be to use gpasswd -a $USER dialout)<br>
<br>
You may have to log out and then in again for the group to become
- effecive.<span style="font-weight: bold;"><br>
+ effective.<span style="font-weight: bold;"><br>
</span>
<p>&nbsp; <br>
&nbsp; <br>
diff --git a/doc/Installing_MSWindows.html b/doc/Installing_MSWindows.html
index bb610cd..21f39ca 100644
--- a/doc/Installing_MSWindows.html
+++ b/doc/Installing_MSWindows.html
@@ -9,8 +9,8 @@
[Netscape]">
<title>Argyll Installation on Microsoft Windows</title>
</head>
- <body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
- vlink="#551a8b">
+ <body style="color: rgb(0, 0, 0);" link="#0000ee" vlink="#551a8b"
+ alink="#ee0000">
<h1> <u>Installing the software on Microsoft Windows<br>
</u></h1>
<h3 style="background-color: rgb(255, 255, 255);"><span
@@ -31,8 +31,8 @@
You should also configure your %PATH% environment variable to give
access to the executables from your command line environment.<br>
<br>
- For <span style="font-weight: bold;">Windows 8</span> &amp; <b>8.1</b>,
- look in<br>
+ For <span style="font-weight: bold;">Windows 8</span>, <b>8.1
+ &amp; 10</b>, look in<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;"></span>Desktop
-&gt; Settings -&gt; Control Panel -&gt; System And Security -&gt;
System -&gt; Advanced System Settings -&gt; Environment Variables<br>
@@ -133,22 +133,24 @@
for these instruments, although it is possible to select the
libusb0.sys driver as an alternative to the default HID driver.<br>
<br>
- If you are using the <b>JETI</b> specbos <span style="font-weight:
- bold;">1211</span><span style="font-weight: bold;"> </span>or <b>1201</b>,
- or the <b>Klein K10A</b> then you may need to install the <a
- href="http://www.ftdichip.com/Drivers/VCP.htm">FTDI Virtual COM
- Port Drivers</a> (VCP), if they are not already on your system.<br>
+ If you are using the <b>JETI</b> specbos <b>1211</b><b>,&nbsp;</b><b>1201</b><b>,
+ 1511, 1501</b> and the <b>Klien K10A</b><b></b> then you may need
+ to install the <a href="http://www.ftdichip.com/Drivers/VCP.htm">FTDI
+ Virtual COM Port Drivers</a> (VCP), if they are not already on
+ your system. You may have to update to the latest FTDI driver to
+ work with the FTDI FT231XS chip that the <b>JETI</b> specbos <b>1511,
+ 1501</b> use.<br>
<br>
Jump to your operating system version:<br>
<br>
- <a href="#WIN8">Windows 8</a><br>
+ <a href="#WIN8">Windows 8, 8.1 &amp; 10</a><br>
<a href="#WINV7">Windows 7</a><br>
<a href="#WINV7">Windows Vista</a><br>
<a href="#WINXP">Windows XP</a><br>
<a href="#WIN2K">Windows 2000</a><br>
<br>
<hr style="width: 100%; height: 2px;"><a name="WIN8"></a><font
- size="+1"><span style="font-weight: bold;">Windows 8 &amp; 8.1</span></font><font
+ size="+1"><span style="font-weight: bold;">Windows 8, 8.1 &amp; 10</span></font><font
size="+1"><span style="font-weight: bold;"></span></font><br>
<br>
<span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
diff --git a/doc/Installing_OSX.html b/doc/Installing_OSX.html
index 76aa98a..1d7bb8d 100644
--- a/doc/Installing_OSX.html
+++ b/doc/Installing_OSX.html
@@ -1,116 +1,116 @@
-<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html;
- charset=windows-1252">
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
- [Netscape]">
- <title>Argyll Installation on Apple OS X</title>
- </head>
- <body>
- <h1> <u>Installing the software on Apple OS X<br>
- </u></h1>
- <br>
- You will need to unpack the downloaded file in such a way that the
- files it contains end up in the location you have chosen to hold its
- contents.<br>
- <br>
- If you want to install it system wide, then you probably want to
- unpack it in the <i>/Applications</i> folder, so that it ends up in
- the <i>/Applications/Argyll_VX.X.X</i> folder.<br>
- Another option is just to install it somewhere under your $HOME
- folder, such as <span style="font-style: italic;">$HOME/</span><i>Argyll_VX.X.X</i>
- or <span style="font-style: italic;">$HOME/</span><i>bin/Argyll_VX.X.X</i>,
- depending on how you like to organize your applications and utility
- programs. ($HOME is the shell symbolic name for your home folder,
- typically /Users/<i>username</i>. Another abbreviation for it is the
- ~ character.)<br>
- <br>
- You can unpack it by control-click on the downloaded file and “Open
- With” BOMArchiveHelper or Archive Utility. Drag the resulting folder
- to where you want it, e.g. into <i>/Applications</i>, <i>$HOME</i>
- or <i>$HOME/bin</i>.<br>
- <br>
- Alternatively you can unpack it on the command line using&nbsp; the
- command <span style="font-weight: bold;">tar -zxf</span> <span
- style="font-weight: bold;">archivename.tgz</span>, which will
- create a folder <span style="font-weight: bold;">Argyll_VX.X.X</span>
- in your current folder, where X.X.X is the version number, and the
- executables will be in <span style="font-weight: bold;">Argyll_VX.X.X/bin</span>
- sub-folder.<br>
- <br>
- Open a Terminal shell. This will be in
- Applications-&gt;Utilities-&gt;Terminal (Dragging it to the dock is
- a good idea to make it more accessible).<br>
- <br>
- You should configure your $PATH environment variable to give the
- shell access to the executable from your command line environment
- without having to spell out the whole path every time, by editing
- your <span style="font-weight: bold;">.profile</span> file, which
- will be in your $HOME folder. You can open a graphical editor on
- this file by using the open command:<br>
- <br>
- &nbsp; open $HOME/.profile<br>
- <br>
- or alternatively, use some other text editor that you are familiar
- with.<br>
- <br>
- Add a line similar to the following line to your .profile file:<br>
- <br>
- &nbsp; PATH=$PATH:/Applications/Argyll_VX.X.X/bin<br>
- <br>
- where "/Applications/Argyll_VX.X.X/bin" is the path to the folder
- that contains the ArgyllCMS executables.<br>
- Save your changes and exit the editor.<br>
- <br>
- If you want further guidance in setting up and using a command line
- environment, then please consult an appropriate tutorial, e.g. &lt;<a
-href="http://heather.cs.ucdavis.edu/matloff/public_html/UnixAndC/Unix/ShellIntro.pdf">ShellIntro</a>&gt;.<br>
- <br>
- The .tgz file also contains several useful reference files (such as
- scanner chart recognition templates, sample illumination spectrum
- etc.) in the <b>ref</b> sub-folder, as well as all the current
- documentation in a <b>doc</b> sub-folder.<br>
- <br>
- For most devices there is nothing special to do. Plug in and go.
- Some devices may not work without some extra help though:<br>
- <h3><a name="ColorMunki"></a><span style="text-decoration:
- underline;">X-Rite ColorMunki</span></h3>
- Some version of X-Rite's ColorMunki drivers released between 2009
- and 2011 install an X-Rite daemon that runs as root and grabs the
- device, preventing any other programs (such as Argyll) from opening
- them. Latter versions seem to be more cooperative, and don't suffer
- from this problem. There are three ways of working around this
- problem:<br>
- <br>
- 1) Turn off the X-Rite service for the ColorMunki. See &lt;<a
- class="moz-txt-link-freetext"
-href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
- <br>
- 2) Run all Argyll programs that need to access the instrument as
- root. For instance:<br>
- <br>
- &nbsp;&nbsp;&nbsp; sudo spotread<br>
- <br>
- and then you will be asked for the root password.<br>
- While these methods will work, they are inconvenient. <br>
- <br>
- 3) Alter the X-Rite drivers Daeomon so that it runs under your user
- account.<br>
- <br>
- To do this you need to edit the script that controls the X-Rite
- Daemon.<br>
- <br>
- &nbsp;&nbsp;&nbsp; cd ~<br>
- &nbsp;&nbsp;&nbsp; whoami<br>
- &nbsp;&nbsp;&nbsp; cp
- /Library/LaunchDaemons/com.xrite.device.colormunki.plist temp.plist<br>
- &nbsp;&nbsp;&nbsp; open temp.plist<br>
- <br>
- and add one child below the root:<br>
- <br>
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=windows-1252">
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Installation on Apple OS X</title>
+ </head>
+ <body>
+ <h1> <u>Installing the software on Apple OS X<br>
+ </u></h1>
+ <br>
+ You will need to unpack the downloaded file in such a way that the
+ files it contains end up in the location you have chosen to hold its
+ contents.<br>
+ <br>
+ If you want to install it system wide, then you probably want to
+ unpack it in the <i>/Applications</i> folder, so that it ends up in
+ the <i>/Applications/Argyll_VX.X.X</i> folder.<br>
+ Another option is just to install it somewhere under your $HOME
+ folder, such as <span style="font-style: italic;">$HOME/</span><i>Argyll_VX.X.X</i>
+ or <span style="font-style: italic;">$HOME/</span><i>bin/Argyll_VX.X.X</i>,
+ depending on how you like to organize your applications and utility
+ programs. ($HOME is the shell symbolic name for your home folder,
+ typically /Users/<i>username</i>. Another abbreviation for it is the
+ ~ character.)<br>
+ <br>
+ You can unpack it by control-click on the downloaded file and “Open
+ With” BOMArchiveHelper or Archive Utility. Drag the resulting folder
+ to where you want it, e.g. into <i>/Applications</i>, <i>$HOME</i>
+ or <i>$HOME/bin</i>.<br>
+ <br>
+ Alternatively you can unpack it on the command line using&nbsp; the
+ command <span style="font-weight: bold;">tar -zxf</span> <span
+ style="font-weight: bold;">archivename.tgz</span>, which will
+ create a folder <span style="font-weight: bold;">Argyll_VX.X.X</span>
+ in your current folder, where X.X.X is the version number, and the
+ executables will be in <span style="font-weight: bold;">Argyll_VX.X.X/bin</span>
+ sub-folder.<br>
+ <br>
+ Open a Terminal shell. This will be in
+ Applications-&gt;Utilities-&gt;Terminal (Dragging it to the dock is
+ a good idea to make it more accessible).<br>
+ <br>
+ You should configure your $PATH environment variable to give the
+ shell access to the executable from your command line environment
+ without having to spell out the whole path every time, by editing
+ your <span style="font-weight: bold;">.profile</span> file, which
+ will be in your $HOME folder. You can open a graphical editor on
+ this file by using the open command:<br>
+ <br>
+ &nbsp; open $HOME/.profile<br>
+ <br>
+ or alternatively, use some other text editor that you are familiar
+ with.<br>
+ <br>
+ Add a line similar to the following line to your .profile file:<br>
+ <br>
+ &nbsp; PATH=$PATH:/Applications/Argyll_VX.X.X/bin<br>
+ <br>
+ where "/Applications/Argyll_VX.X.X/bin" is the path to the folder
+ that contains the ArgyllCMS executables.<br>
+ Save your changes and exit the editor.<br>
+ <br>
+ If you want further guidance in setting up and using a command line
+ environment, then please consult an appropriate tutorial, e.g. &lt;<a
+href="http://heather.cs.ucdavis.edu/matloff/public_html/UnixAndC/Unix/ShellIntro.pdf">ShellIntro</a>&gt;.<br>
+ <br>
+ The .tgz file also contains several useful reference files (such as
+ scanner chart recognition templates, sample illumination spectrum
+ etc.) in the <b>ref</b> sub-folder, as well as all the current
+ documentation in a <b>doc</b> sub-folder.<br>
+ <br>
+ For most devices there is nothing special to do. Plug in and go.
+ Some devices may not work without some extra help though:<br>
+ <h3><a name="ColorMunki"></a><span style="text-decoration:
+ underline;">X-Rite ColorMunki</span></h3>
+ Some version of X-Rite's ColorMunki drivers released between 2009
+ and 2011 install an X-Rite daemon that runs as root and grabs the
+ device, preventing any other programs (such as Argyll) from opening
+ them. Latter versions seem to be more cooperative, and don't suffer
+ from this problem. There are three ways of working around this
+ problem:<br>
+ <br>
+ 1) Turn off the X-Rite service for the ColorMunki. See &lt;<a
+ class="moz-txt-link-freetext"
+href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
+ <br>
+ 2) Run all Argyll programs that need to access the instrument as
+ root. For instance:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; sudo spotread<br>
+ <br>
+ and then you will be asked for the root password.<br>
+ While these methods will work, they are inconvenient. <br>
+ <br>
+ 3) Alter the X-Rite drivers Daeomon so that it runs under your user
+ account.<br>
+ <br>
+ To do this you need to edit the script that controls the X-Rite
+ Daemon.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cd ~<br>
+ &nbsp;&nbsp;&nbsp; whoami<br>
+ &nbsp;&nbsp;&nbsp; cp
+ /Library/LaunchDaemons/com.xrite.device.colormunki.plist temp.plist<br>
+ &nbsp;&nbsp;&nbsp; open temp.plist<br>
+ <br>
+ and add one child below the root:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;">Item&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -122,9 +122,10 @@ Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs
- Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- </span><br>
- &nbsp;&nbsp;&nbsp; UserName &nbsp;
+
+ Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span><br>
+ &nbsp;&nbsp;&nbsp; UserName &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -136,62 +137,63 @@ string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n
- myusername<br>
- <br>
- where "myusername" is your username shown by whoami, and save the
- file. You then need to copy the modified file back: <br>
- <br>
- &nbsp;&nbsp;&nbsp; sudo cp temp.plist
- /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
- <br>
- You will then need to restart the machine for this change to take
- effect, or invoke the following commands:<br>
- <br>
- &nbsp;&nbsp; sudo launchctl unload
- /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
- &nbsp;&nbsp; sudo launchctl load
- /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that after running
- Argyll tools, you may have to turn the X-Rite service off then on
- again, or disconnect and reconnect the instrument.<br>
- <br>
- <h3><a name="ColorMunki"></a><span style="text-decoration:
- underline;">X-Rite EyeOne Pro</span><br>
- </h3>
- Some version of X-Rite's EyeOne Pro drivers drivers released between
- 2009 and 2011 install an X-Rite daemon that runs as root and grabs
- the device, preventing any other programs (such as Argyll) from
- opening them. Latter versions seem to be more cooperative, and don't
- suffer from this problem. There are three ways of working around
- this problem:<br>
- <br>
- 1) Turn off the X-Rite service for the EyeOne Pro. See &lt;<a
- class="moz-txt-link-freetext"
-href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
- <br>
- 2) Run all Argyll programs that need to access the instrument as
- root. For instance:<br>
- <br>
- &nbsp;&nbsp;&nbsp; sudo spotread<br>
- <br>
- and then you will be asked for the root password.<br>
- While these methods will work, they are inconvenient. <br>
- <br>
- 3) Alter the X-Rite drivers Daemon so that it runs under your user
- account.<br>
- <br>
- To do this you need to edit the script that controls the X-Rite
- Daemon.<br>
- <br>
- &nbsp;&nbsp;&nbsp; cd ~<br>
- &nbsp;&nbsp;&nbsp; whoami<br>
- &nbsp;&nbsp;&nbsp; cp
- /Library/LaunchDaemons/com.xrite.device.i1.plist temp.plist<br>
- &nbsp;&nbsp;&nbsp; open temp.plist<br>
- <br>
- and add one child below the root:<br>
- <br>
+
+ myusername<br>
+ <br>
+ where "myusername" is your username shown by whoami, and save the
+ file. You then need to copy the modified file back: <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; sudo cp temp.plist
+ /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+ <br>
+ You will then need to restart the machine for this change to take
+ effect, or invoke the following commands:<br>
+ <br>
+ &nbsp;&nbsp; sudo launchctl unload
+ /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+ &nbsp;&nbsp; sudo launchctl load
+ /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that after running
+ Argyll tools, you may have to turn the X-Rite service off then on
+ again, or disconnect and reconnect the instrument.<br>
+ <br>
+ <h3><a name="ColorMunki"></a><span style="text-decoration:
+ underline;">X-Rite EyeOne Pro</span><br>
+ </h3>
+ Some version of X-Rite's EyeOne Pro drivers drivers released between
+ 2009 and 2011 install an X-Rite daemon that runs as root and grabs
+ the device, preventing any other programs (such as Argyll) from
+ opening them. Latter versions seem to be more cooperative, and don't
+ suffer from this problem. There are three ways of working around
+ this problem:<br>
+ <br>
+ 1) Turn off the X-Rite service for the EyeOne Pro. See &lt;<a
+ class="moz-txt-link-freetext"
+href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
+ <br>
+ 2) Run all Argyll programs that need to access the instrument as
+ root. For instance:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; sudo spotread<br>
+ <br>
+ and then you will be asked for the root password.<br>
+ While these methods will work, they are inconvenient. <br>
+ <br>
+ 3) Alter the X-Rite drivers Daemon so that it runs under your user
+ account.<br>
+ <br>
+ To do this you need to edit the script that controls the X-Rite
+ Daemon.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cd ~<br>
+ &nbsp;&nbsp;&nbsp; whoami<br>
+ &nbsp;&nbsp;&nbsp; cp
+ /Library/LaunchDaemons/com.xrite.device.i1.plist temp.plist<br>
+ &nbsp;&nbsp;&nbsp; open temp.plist<br>
+ <br>
+ and add one child below the root:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;">Item&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -203,9 +205,10 @@ Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs
- Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- </span><br>
- &nbsp;&nbsp;&nbsp; UserName &nbsp;
+
+ Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span><br>
+ &nbsp;&nbsp;&nbsp; UserName &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -217,26 +220,27 @@ string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n
- myusername<br>
- <br>
- where "myusername" is your username shown by whoami, and save the
- file. You then need to copy the modified file back: <br>
- <br>
- &nbsp;&nbsp;&nbsp; sudo cp temp.plist
- /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
- <br>
- You will then need to restart the machine for this change to take
- effect, or invoke the following commands:<br>
- <br>
- &nbsp;&nbsp; sudo launchctl unload
- /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
- &nbsp;&nbsp; sudo launchctl load
- /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that after running
- Argyll tools, you may have to turn the X-Rite service off then on
- again, or disconnect and reconnect the instrument.<br>
- <br>
+
+ myusername<br>
+ <br>
+ where "myusername" is your username shown by whoami, and save the
+ file. You then need to copy the modified file back: <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; sudo cp temp.plist
+ /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+ <br>
+ You will then need to restart the machine for this change to take
+ effect, or invoke the following commands:<br>
+ <br>
+ &nbsp;&nbsp; sudo launchctl unload
+ /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+ &nbsp;&nbsp; sudo launchctl load
+ /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that after running
+ Argyll tools, you may have to turn the X-Rite service off then on
+ again, or disconnect and reconnect the instrument.<br>
+ <br>
<h3><a name="specbos"></a><span style="text-decoration: underline;">JETI
specbos
@@ -248,68 +252,70 @@ specbos
- 1201 and 1211</span> and <u>Klein K10A</u><br>
- </h3>
- <br>
- If you are using the <b>JETI</b> specbos <span style="font-weight:
- bold;">1211</span><span style="font-weight: bold;"> </span>and <b>1201</b>,
- or the <b>Klein K10A</b> then you may need to install the <a
- href="http://www.ftdichip.com/Drivers/VCP.htm">FTDI Virtual COM
- Port Drivers</a> (VCP), if they are not already on your system.<br>
- <br>
- <h3><a name="HCFR"></a><u>HCFR Colorimeter</u></h3>
- The default OS X class drivers will grab this device, preventing
- Argyll from accessing it. To overcome this, you need to install a
- codeless kernel extension if you wish to use the HCFR colorimeter,
- that prevents this from happening. From the command line you need to
- create a folder called Argyll.kext somewhere convenient, and then
- place in it one file called Info.plist, containing the following:<br>
- <br>
- &nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
- &nbsp;&nbsp; &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>
- &nbsp;&nbsp; &lt;!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST
- 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;<br>
- &nbsp;&nbsp; &lt;plist version="1.0"&gt;<br>
- &nbsp;&nbsp; &lt;dict&gt;<br>
- &nbsp; &nbsp;&nbsp; &nbsp;
- &lt;key&gt;CFBundleDevelopmentRegion&lt;/key&gt;
- &lt;string&gt;English&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp;
- &lt;key&gt;CFBundleGetInfoString&lt;/key&gt; &lt;string&gt;Libusb
- USB device Shield&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
- &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
- &lt;string&gt;com.libusb.USB_Shield&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp;
- &lt;key&gt;CFBundleInfoDictionaryVersion&lt;/key&gt;
- &lt;string&gt;6.0&lt;/string&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleName&lt;/key&gt;
- &lt;string&gt;Libusb USB device Shield&lt;/string&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp;
- &lt;key&gt;CFBundlePackageType&lt;/key&gt;
- &lt;string&gt;KEXT&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;CFBundleSignature&lt;/key&gt;
- &lt;string&gt;????&lt;/string&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleVersion&lt;/key&gt;
- &lt;string&gt;6.0&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
- &lt;key&gt;IOKitPersonalities&lt;/key&gt;<br>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dict&gt;<br>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
- &lt;key&gt;HCFR&lt;/key&gt;<br>
- &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;
- &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
- &lt;string&gt;com.apple.driver.AppleUSBComposite&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp; &lt;key&gt;IOClass&lt;/key&gt;
- &lt;string&gt;AppleUSBComposite&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
- &nbsp; &lt;key&gt;IOProviderClass&lt;/key&gt;
- &lt;string&gt;IOUSBDevice&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp; &lt;key&gt;idVendor&lt;/key&gt;
- &lt;integer&gt;1243&lt;/integer&gt;<br>
+
+ 1201 and 1211</span> and <u>Klein K10A</u><br>
+ </h3>
+ <br>
+ If you are using the <b>JETI</b> specbos <b>1211</b><b>,&nbsp;</b><b>1201</b><b>,
+ 1511, 1501</b> and the <b>Klien K10A</b> then you may need to
+ install the <a href="http://www.ftdichip.com/Drivers/VCP.htm">FTDI
+ Virtual COM Port Drivers</a> (VCP), if they are not already on
+ your system. You may have to update to the latest FTDI driver to
+ work with the FTDI FT231XS chip that the <b>JETI</b> specbos <b>1511,
+ 1501</b> use.<br>
+ <h3><a name="HCFR"></a><u>HCFR Colorimeter</u></h3>
+ The default OS X class drivers will grab this device, preventing
+ Argyll from accessing it. To overcome this, you need to install a
+ codeless kernel extension if you wish to use the HCFR colorimeter,
+ that prevents this from happening. From the command line you need to
+ create a folder called Argyll.kext somewhere convenient, and then
+ place in it one file called Info.plist, containing the following:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
+ &nbsp;&nbsp; &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>
+ &nbsp;&nbsp; &lt;!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST
+ 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;<br>
+ &nbsp;&nbsp; &lt;plist version="1.0"&gt;<br>
+ &nbsp;&nbsp; &lt;dict&gt;<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;
+ &lt;key&gt;CFBundleDevelopmentRegion&lt;/key&gt;
+ &lt;string&gt;English&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp;
+ &lt;key&gt;CFBundleGetInfoString&lt;/key&gt; &lt;string&gt;Libusb
+ USB device Shield&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
+ &lt;string&gt;com.libusb.USB_Shield&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp;
+ &lt;key&gt;CFBundleInfoDictionaryVersion&lt;/key&gt;
+ &lt;string&gt;6.0&lt;/string&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleName&lt;/key&gt;
+ &lt;string&gt;Libusb USB device Shield&lt;/string&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp;
+ &lt;key&gt;CFBundlePackageType&lt;/key&gt;
+ &lt;string&gt;KEXT&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;CFBundleSignature&lt;/key&gt;
+ &lt;string&gt;????&lt;/string&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleVersion&lt;/key&gt;
+ &lt;string&gt;6.0&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &lt;key&gt;IOKitPersonalities&lt;/key&gt;<br>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dict&gt;<br>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
+ &lt;key&gt;HCFR&lt;/key&gt;<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;
+ &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
+ &lt;string&gt;com.apple.driver.AppleUSBComposite&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp; &lt;key&gt;IOClass&lt;/key&gt;
+ &lt;string&gt;AppleUSBComposite&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
+ &nbsp; &lt;key&gt;IOProviderClass&lt;/key&gt;
+ &lt;string&gt;IOUSBDevice&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; &lt;key&gt;idVendor&lt;/key&gt;
+ &lt;integer&gt;1243&lt;/integer&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -320,35 +326,36 @@ specbos
- &nbsp; &lt;key&gt;idProduct&lt;/key&gt;
- &lt;integer&gt;91&lt;/integer&gt;<br>
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &lt;/dict&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp; &lt;/dict&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp;
- &lt;key&gt;OSBundleCompatibleVersion&lt;/key&gt;
- &lt;string&gt;1.8&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;OSBundleLibraries&lt;/key&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
- &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &lt;key&gt;com.apple.kernel.iokit&lt;/key&gt;
- &lt;string&gt;6.0&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dict&gt;<br>
- &nbsp;&nbsp; &lt;/dict&gt;<br>
- &nbsp;&nbsp; &lt;/plist&gt;<br>
- &nbsp; &nbsp; ----------------- cut here ---------------------<br>
- <br>
- (You can also copy this from the source installation in
- usb/Argyll.kext)<br>
- <br>
- You then need to install it by using:<br>
- <br>
- &nbsp; sudo cp -R Argyll.kext /System/Library/Extensions<br>
- <br>
- supplying the appropriate root password when prompted.<br>
- Reboot the system to activate the extension.<br>
- <br>
- <p><br>
- </p>
- </body>
-</html>
+
+ &nbsp; &lt;key&gt;idProduct&lt;/key&gt;
+ &lt;integer&gt;91&lt;/integer&gt;<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &lt;/dict&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp; &lt;/dict&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp;
+ &lt;key&gt;OSBundleCompatibleVersion&lt;/key&gt;
+ &lt;string&gt;1.8&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;OSBundleLibraries&lt;/key&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
+ &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &lt;key&gt;com.apple.kernel.iokit&lt;/key&gt;
+ &lt;string&gt;6.0&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dict&gt;<br>
+ &nbsp;&nbsp; &lt;/dict&gt;<br>
+ &nbsp;&nbsp; &lt;/plist&gt;<br>
+ &nbsp; &nbsp; ----------------- cut here ---------------------<br>
+ <br>
+ (You can also copy this from the source installation in
+ usb/Argyll.kext)<br>
+ <br>
+ You then need to install it by using:<br>
+ <br>
+ &nbsp; sudo cp -R Argyll.kext /System/Library/Extensions<br>
+ <br>
+ supplying the appropriate root password when prompted.<br>
+ Reboot the system to activate the extension.<br>
+ <br>
+ <p><br>
+ </p>
+ </body>
+</html>
diff --git a/doc/JETI_1501.jpg b/doc/JETI_1501.jpg
new file mode 100644
index 0000000..ac348d6
--- /dev/null
+++ b/doc/JETI_1501.jpg
Binary files differ
diff --git a/icc/License.txt b/doc/License4.txt
index bd0c4f2..61be41a 100644
--- a/icc/License.txt
+++ b/doc/License4.txt
@@ -1,5 +1,5 @@
*************************************************************************
-Copyright (c) 1997-2013 Graeme W. Gill
+Copyright (c) 1997-2015 Graeme W. Gill
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/doc/Performance.html b/doc/Performance.html
index 340cec0..c45084b 100644
--- a/doc/Performance.html
+++ b/doc/Performance.html
@@ -2,139 +2,72 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
- charset=ISO-8859-1">
+ charset=windows-1252">
<meta http-equiv="content-type" content="text/html;
- charset=ISO-8859-1">
+ charset=windows-1252">
<meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
[Netscape]">
<title>Argyll Performance Tuning</title>
</head>
<body>
- <h2>
- <u>Performance Tuning</u></h2>
+ <h2> <u>Performance Tuning</u></h2>
<br>
Some operations in Argyll can be particularly slow, so it is worth
examining ways of improving performance, or trading memory
- consumption
- for performance.<br>
+ consumption for performance.<br>
+ <br>
+ (See <a href="Environment.html">here</a> for how to set Environment
+ variables.)<br>
<h3>Creating Device Links and Profiles<br>
</h3>
In creating device links or the B2A tables of profiles, the
- execution
- time is often dominated by the inversion of forward
- color lookup values. An in-memory cache is employed to speed up this
+ execution time is often dominated by the inversion of forward color
+ lookup values. An in-memory cache is employed to speed up this
operation, by keeping computed values in case they can be used more
than once. The amount of memory used for caching these values is
pre-set within the inversion code, and by default is set to use half
- of
- the available RAM on the system, with a minimum of 50 Mbytes.<br>
+ of the available RAM on the system, with a minimum of 50 Mbytes.<br>
<br>
The reverse cache size can be changed by setting an environment
- variable
- <span style="font-weight: bold;">ARGYLL_REV_CACHE_MULT</span> to a
- number greater or less than than 1.0 This will multiply the size of
- the
- cache by that number (i.e. 1.5 would increase the cache size by 50%,
- 0.5 would halve it).<br>
+ variable <span style="font-weight: bold;">ARGYLL_REV_CACHE_MULT</span>
+ to a number greater or less than than 1.0 This will multiply the
+ size of the cache by that number (i.e. 1.5 would increase the cache
+ size by 50%, 0.5 would halve it).<br>
<br>
If you find that <span style="font-weight: bold;">colprof</span>
- or&nbsp; <span style="font-weight: bold;">collink</span>
- are working very slowly, but that your CPU's are nearly idle, then
- this
+ or&nbsp; <span style="font-weight: bold;">collink</span> are
+ working very slowly, but that your CPU's are nearly idle, then this
is a sign of disk swapping, and that too much memory is being
requested.&nbsp; This can be because other applications are also
- using
- memory, or Argyll's default setting tries to use more memory than is
- actually available. You can try shutting down other applications
- when
- this happens, or you can <span style="font-weight: bold;">lower</span>
- the amount of memory Argyll uses by setting <span
- style="font-weight: bold;">ARGYLL_REV_CACHE_MULT</span> to a value
- less than 1.0 (ie. try 0.5). <br>
+ using memory, or Argyll's default setting tries to use more memory
+ than is actually available. You can try shutting down other
+ applications when this happens, or you can <span
+ style="font-weight: bold;">lower</span> the amount of memory
+ Argyll uses by setting <span style="font-weight: bold;">ARGYLL_REV_CACHE_MULT</span>
+ to a value less than 1.0 (ie. try 0.5). <br>
<br>
If you have a lot of memory available, you can try increasing the
cache size to use more of the available RAM (particularly if you get
- a
- "Warning - Reverse Cell Cache exhausted,
- processing in chunks" message during processing), but if you set it
- to
- a value too near 2.0 you risk disk swapping, which can slow progress
- to
- a crawl.<br>
+ a "Warning - Reverse Cell Cache exhausted, processing in chunks"
+ message during processing), but if you set it to a value too near
+ 2.0 you risk disk swapping, which can slow progress to a crawl.<br>
<br>
If you have a lot of memory available, then a second adjustment that
- can make a great difference to the time taken
- in creating B2A tables is the resolution of the inverse lookup
- acceleration grid. The finer the grid, the less searching is needed
- to
- locate the input colorspace values that
- correspond to a target output color value, but the greater the
- memory
- used in this
- structure, and the greater the setup time needed to initialize the
- acceleration grid. The <span style="font-weight: bold;">ARGYLL_REV_ACC_GRID_RES_MULT</span>
+ can make a great difference to the time taken in creating B2A tables
+ is the resolution of the inverse lookup acceleration grid. The finer
+ the grid, the less searching is needed to locate the input
+ colorspace values that correspond to a target output color value,
+ but the greater the memory used in this structure, and the greater
+ the setup time needed to initialize the acceleration grid. The <span
+ style="font-weight: bold;">ARGYLL_REV_ACC_GRID_RES_MULT</span>
environment variable can alter the default resolution by a scale
factor. A value of 0.5 for instance, would halve the resolution
(typically meaning 1/8 th. the total number of grid entries and
memory), while a value of 2.0 would double it, typically resulting
- in 8
- times the memory usage. Increasing the resolution too much will
- reduce
- the available memory for the reverse cache, and greatly increase
- setup
- time.<br>
- <br>
- <h3>Setting an environment variable:</h3>
- <br>
- To set an environment variable an MSWindows DOS shell, either use
- set,
- e.g.;<br>
- <br>
- &nbsp;&nbsp;&nbsp; set ARGYLL_REV_CACHE_MULT=1.5<br>
- <br>
- which will set the value for that session, or set it in<br>
- <br>
- Control Panel-&gt;System-&gt;Advanced-&gt;Environment Variables..<br>
- <br>
- in either user or system variables.<br>
- <br>
- You can examine individual variables using<br>
- <br>
- &nbsp;&nbsp;&nbsp; echo %VARIABLE_NAME%<br>
- <br>
- or see all of them using<br>
- <br>
- &nbsp;&nbsp; set<br>
- <br>
- <br>
- For OS X or Linux, the exact procedure will depend on the shell you
- are
- running, but<br>
- is usually something like:<br>
- <br>
- &nbsp;&nbsp;&nbsp; export ARGYLL_REV_CACHE_MULT=1.5<br>
- or<br>
- &nbsp;&nbsp;&nbsp; set ARGYLL_REV_CACHE_MULT=1.5<br>
- or<br>
- &nbsp;&nbsp;&nbsp; ARGYLL_REV_CACHE_MULT=1.5<br>
- <br>
- and may need separately exporting, something like:<br>
- <br>
- &nbsp;&nbsp;&nbsp; export ARGYLL_REV_CACHE_MULT<br>
- <br>
- Generally it should be configured in the shell start-up
- script,&nbsp;
- if you
- want the setting to be used<br>
- for every session.<br>
- <br>
- You can examine individual variables using<br>
- <br>
- &nbsp;&nbsp;&nbsp; echo $VARIABLE_NAME<br>
- <br>
- or see all of them using<br>
+ in 8 times the memory usage. Increasing the resolution too much will
+ reduce the available memory for the reverse cache, and greatly
+ increase setup time.<br>
<br>
- &nbsp;&nbsp; set<br>
<br>
<br>
<br>
diff --git a/doc/Scenarios.html b/doc/Scenarios.html
index c8bb154..8aa5d64 100644
--- a/doc/Scenarios.html
+++ b/doc/Scenarios.html
@@ -1,134 +1,134 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>Argyll Usage Scenarios</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- </head>
- <body>
- <h2><u>Typical usage Scenarios and Examples</u></h2>
- Choose a task from the list below. For more details on alternative
- options, follow the links to the individual tools being used.<br>
- <br>
- Note that by default it is assumed that ICC profile have the file
- extension <span style="font-weight: bold;">.icm</span>, but that on
- Apple OS X and Unix/Linux platforms, the <span style="font-weight:
- bold;">.icc</span> extension is expected and should be used.<br>
- <h4><a href="#PM1">Profiling Displays</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1a">Checking you can access your
- display<br>
- </a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1b">Adjusting and Calibrating a
- displays</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1c">Adjusting, calibrating and
- profiling in one step<br>
- </a><span style="font-weight: bold;"></span><span
- style="font-weight: bold;"></span><span style="text-decoration:
- underline;"></span></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PM2">Creating display test values</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PM3">Taking readings from a
- display</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PM4">Creating a display profile</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
- href="#PM5">Installing a display profile</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
- href="#PM6">Expert tips when measuring displays</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
- href="#PM7">Calibrating and profiling a display that doesn't
- have VideoLUT access.</a></h4>
- <h4><br>
- <a href="#PS1">Profiling Scanners and other input devices such as
- cameras<br>
- </a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PS2">Types of test charts</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PS3">Taking readings from a
- scanner</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PS4">Creating a scanner profile</a></h4>
- <h4><br>
- <a href="#PP1">Profiling Printers</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PP2">Creating a print profile
- test chart</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PP2b">Printing a
- print profile test chart</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PP3">Reading a print test chart
- using an instrument</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PP4">Reading a print test chart
- using a scanner</a></h4>
- <h4> </h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PP5">Creating a printer profile<br>
- </a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PP6">Choosing a black generation
- curve</a></h4>
- <br>
- <h4><a href="Scenarios.html#PC1">Calibrating Printers</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC2">Calibrated
- print workflows</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC3">Creating a
- print calibration test chart</a></h4>
- <h4> </h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC4">Creating a
- printer calibration<br>
- </a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC5">Using a printer
- calibration</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PC6">How profile ink limits are
- handled when calibration is being used<br>
- </a></h4>
- <h4> <a href="#LP1">Linking Profiles</a></h4>
- <p>&nbsp;&nbsp;&nbsp; <b><a href="#LP2">Image dependent gamut
- mapping using device links</a></b><br>
- </p>
- <p>&nbsp;&nbsp;&nbsp; <b><a href="#LP2">Soft Proofing Link</a></b><br>
- </p>
- <h4> <a href="#TR1">Transforming colorspaces of raster files</a></h4>
- <h4></h4>
- <h4> <a href="#TV1">Creating Video Calibration 3DLuts</a></h4>
- <h4><a href="Scenarios.html#TV2">Verifying Video Calibration 3DLuts</a></h4>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <h3><a name="PM1"></a>Profiling Displays</h3>
- Argyll supports adjusting, calibrating and profiling of displays
- using one of a number of instruments - see <a
- href="instruments.html">instruments</a> for a current list.&nbsp;
- Adjustment and calibration are prior steps to profiling, in which
- the display is adjusted using it's screen controls,&nbsp; and then
- per channel lookup tables are created to make it meet a well behaved
- response of the desired type. The&nbsp; process following that of
- creating a display profile is then similar to that of all other
- output devices :- first a set of device colorspace test values needs
- to be created to exercise the display, then these values need to be
- displayed, while taking measurements of the resulting colors using
- the instrument. Finally, the device value/measured color values need
- to be converted into an ICC profile.<br>
- <br>
- <h3><a name="PM1a"></a>Checking you can access your display<br>
- </h3>
- You might first want to check that you are accessing and can
- calibrate your display. You can do this using the <a
- href="dispwin.html">dispwin</a><span style="font-weight: bold;"></span>
- tool<span style="font-weight: bold;">.</span> If you just run <span
- style="font-weight: bold;">dispwin</span> it will create a test
- window and run through a series of test colors before checking that
- the VideoLUT can be accessed by the display. If you invoke the usage
- for <span style="font-weight: bold;">dispwin</span> (by giving it
- an unrecognized option, e.g. <span style="font-weight: bold;">-?</span>)
- then it will show a list of available displays next to the <span
- style="font-weight: bold;"><span style="font-weight: bold;">-d</span></span>
- flag. Make sure that you are accessing the display you intend to
- calibrate and profile, and that the VideoLUT is effective (the <span
- style="font-weight: bold;">-r</span> flag can be used to just run
- the VideoLUT test). You can also try clearing the VideoLUTs using
- the <span style="font-weight: bold;">-c</span> flag, and loading a
- deliberately strange looking calibration <span style="font-weight:
- bold;">strange.cal</span> that is provided in the Argyll <span
- style="font-weight: bold;">ref</span> directory.<br>
- <br>
- Note that calibrating and/or profiling <span style="font-weight:
- bold;">remote</span> displays is possible using X11 or a web
- browser (see <span style="font-weight: bold;">-d</span> option of
- dispcal and dispread), or by using some external program to send
- test colors to a display (see <span style="font-weight: bold;">-C</span>
- and <span style="font-weight: bold;">-M</span> options of dispcal
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Argyll Usage Scenarios</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ </head>
+ <body>
+ <h2><u>Typical usage Scenarios and Examples</u></h2>
+ Choose a task from the list below. For more details on alternative
+ options, follow the links to the individual tools being used.<br>
+ <br>
+ Note that by default it is assumed that ICC profile have the file
+ extension <span style="font-weight: bold;">.icm</span>, but that on
+ Apple OS X and Unix/Linux platforms, the <span style="font-weight:
+ bold;">.icc</span> extension is expected and should be used.<br>
+ <h4><a href="#PM1">Profiling Displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1a">Checking you can access your
+ display<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1b">Adjusting and Calibrating a
+ displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1c">Adjusting, calibrating and
+ profiling in one step<br>
+ </a><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span><span style="text-decoration:
+ underline;"></span></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM2">Creating display test values</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PM3">Taking readings from a
+ display</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PM4">Creating a display profile</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM5">Installing a display profile</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM6">Expert tips when measuring displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM7">Calibrating and profiling a display that doesn't
+ have VideoLUT access.</a></h4>
+ <h4><br>
+ <a href="#PS1">Profiling Scanners and other input devices such as
+ cameras<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS2">Types of test charts</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS3">Taking readings from a
+ scanner</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS4">Creating a scanner profile</a></h4>
+ <h4><br>
+ <a href="#PP1">Profiling Printers</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP2">Creating a print profile
+ test chart</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PP2b">Printing a
+ print profile test chart</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP3">Reading a print test chart
+ using an instrument</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP4">Reading a print test chart
+ using a scanner</a></h4>
+ <h4> </h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PP5">Creating a printer profile<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PP6">Choosing a black generation
+ curve</a></h4>
+ <br>
+ <h4><a href="Scenarios.html#PC1">Calibrating Printers</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC2">Calibrated
+ print workflows</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC3">Creating a
+ print calibration test chart</a></h4>
+ <h4> </h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC4">Creating a
+ printer calibration<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC5">Using a printer
+ calibration</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PC6">How profile ink limits are
+ handled when calibration is being used<br>
+ </a></h4>
+ <h4> <a href="#LP1">Linking Profiles</a></h4>
+ <p>&nbsp;&nbsp;&nbsp; <b><a href="#LP2">Image dependent gamut
+ mapping using device links</a></b><br>
+ </p>
+ <p>&nbsp;&nbsp;&nbsp; <b><a href="#LP2">Soft Proofing Link</a></b><br>
+ </p>
+ <h4> <a href="#TR1">Transforming colorspaces of raster files</a></h4>
+ <h4></h4>
+ <h4> <a href="#TV1">Creating Video Calibration 3DLuts</a></h4>
+ <h4><a href="Scenarios.html#TV2">Verifying Video Calibration 3DLuts</a></h4>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <h3><a name="PM1"></a>Profiling Displays</h3>
+ Argyll supports adjusting, calibrating and profiling of displays
+ using one of a number of instruments - see <a
+ href="instruments.html">instruments</a> for a current list.&nbsp;
+ Adjustment and calibration are prior steps to profiling, in which
+ the display is adjusted using it's screen controls,&nbsp; and then
+ per channel lookup tables are created to make it meet a well behaved
+ response of the desired type. The&nbsp; process following that of
+ creating a display profile is then similar to that of all other
+ output devices :- first a set of device colorspace test values needs
+ to be created to exercise the display, then these values need to be
+ displayed, while taking measurements of the resulting colors using
+ the instrument. Finally, the device value/measured color values need
+ to be converted into an ICC profile.<br>
+ <br>
+ <h3><a name="PM1a"></a>Checking you can access your display<br>
+ </h3>
+ You might first want to check that you are accessing and can
+ calibrate your display. You can do this using the <a
+ href="dispwin.html">dispwin</a><span style="font-weight: bold;"></span>
+ tool<span style="font-weight: bold;">.</span> If you just run <span
+ style="font-weight: bold;">dispwin</span> it will create a test
+ window and run through a series of test colors before checking that
+ the VideoLUT can be accessed by the display. If you invoke the usage
+ for <span style="font-weight: bold;">dispwin</span> (by giving it
+ an unrecognized option, e.g. <span style="font-weight: bold;">-?</span>)
+ then it will show a list of available displays next to the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">-d</span></span>
+ flag. Make sure that you are accessing the display you intend to
+ calibrate and profile, and that the VideoLUT is effective (the <span
+ style="font-weight: bold;">-r</span> flag can be used to just run
+ the VideoLUT test). You can also try clearing the VideoLUTs using
+ the <span style="font-weight: bold;">-c</span> flag, and loading a
+ deliberately strange looking calibration <span style="font-weight:
+ bold;">strange.cal</span> that is provided in the Argyll <span
+ style="font-weight: bold;">ref</span> directory.<br>
+ <br>
+ Note that calibrating and/or profiling <span style="font-weight:
+ bold;">remote</span> displays is possible using X11 or a web
+ browser (see <span style="font-weight: bold;">-d</span> option of
+ dispcal and dispread), or by using some external program to send
+ test colors to a display (see <span style="font-weight: bold;">-C</span>
+ and <span style="font-weight: bold;">-M</span> options of dispcal
and dispread), but you may want to refer to <a href="#PM7">Calibrating
@@ -184,26 +184,29 @@
- and profiling a display that doesn't have VideoLUT access</a>.<br>
- <br>
- <h3><a name="PM1b"></a>Adjusting and Calibrating Displays</h3>
- Please read <a href="calvschar.html">What's the difference between
- Calibration and Characterization ?</a> if you are unclear as to
- the difference .<br>
- <br>
- The first step is to decide what the target should be for adjustment
- and calibration. This boils down to three things: The desired
- brightness, the desired white point, and the desired response curve.
- The native brightness and white points of a display may be different
- to the desired characteristics for some purposes. For instance, for
- graphic arts use, it might be desirable to run with a warmer white
- point of about 5000 degrees Kelvin, rather than the default display
- white point of 6500 to 9000 Kelvin. Some LCD displays are too bright
- to compare to printed material under available lighting, so it might
- be desirable to reduce the maximum brightness.<br>
- <br>
- You can run <a href="dispcal.html#r">dispcal -r</a> to check on how
- your display is currently set up. (you may have to run this as <span
+
+
+
+ and profiling a display that doesn't have VideoLUT access</a>.<br>
+ <br>
+ <h3><a name="PM1b"></a>Adjusting and Calibrating Displays</h3>
+ Please read <a href="calvschar.html">What's the difference between
+ Calibration and Characterization ?</a> if you are unclear as to
+ the difference .<br>
+ <br>
+ The first step is to decide what the target should be for adjustment
+ and calibration. This boils down to three things: The desired
+ brightness, the desired white point, and the desired response curve.
+ The native brightness and white points of a display may be different
+ to the desired characteristics for some purposes. For instance, for
+ graphic arts use, it might be desirable to run with a warmer white
+ point of about 5000 degrees Kelvin, rather than the default display
+ white point of 6500 to 9000 Kelvin. Some LCD displays are too bright
+ to compare to printed material under available lighting, so it might
+ be desirable to reduce the maximum brightness.<br>
+ <br>
+ You can run <a href="dispcal.html#r">dispcal -r</a> to check on how
+ your display is currently set up. (you may have to run this as <span
style="text-decoration: underline; color: rgb(204, 51, 204);">dispcal
-yl
@@ -265,331 +268,343 @@
- -r</span> for an LCD display, or <span style="text-decoration:
- underline; color: rgb(204, 51, 204);">dispcal -yc -r</span> for a
- CRT display with most of the colorimeter instruments. If so, this
- will apply to all of the following examples.)<br>
- <br>
- Once this is done, <a href="dispcal.html">dispcal</a> can be run to
- guide you through the display adjustments, and then calibrate it. By
- default, the brightness and white point will be kept the same as the
- devices natural brightness and white point. The default response
- curve is a gamma of 2.4, except for Apple OS X systems prior to 10.6
- where a gamma of 1.8 is the default. 2.4 is close to that of&nbsp;
- many monitors, and close to that of the sRGB colorspace. <br>
- <br>
- A typical calibration that leaves the brightness and white point
- alone, might be:<br>
- <br>
- <a href="dispcal.html">dispcal</a> -v TargetA<br>
- <br>
- which will result in a "TargetA.cal" calibration file, that can then
- be used during the profiling stage.<br>
- <br>
- If the absolutely native response of the display is desired during
- profiling, then calibration should be skipped, and the linear.cal
- file from the "ref" directory used instead as the argument to the -k
- flag of <span style="font-weight: bold;">dispread</span>.<br>
- <br>
- <b>Dispcal</b> will display a test window in the middle of the
- screen, and issue a series of instructions about placing the
- instrument on the display. You may need to make sure that the
- display cursor is not in the test window, and it may also be
- necessary to disable any screensaver and powersavers before starting
- the process, although both <span style="font-weight: bold;">dispcal</span>
- and <span style="font-weight: bold;">dispread</span> will attempt
- to do this for you. It's also highly desirable on CRT's, to clear
- your screen of any white or bright background images or windows
- (running your shell window with white text on a black background
- helps a lot here.), or at least keep any bright areas away from the
- test window, and be careful not to change anything on the display
- while the readings are taken. Lots of bright images or windows can
- affect the ability to measure the black point accurately, and
- changing images on the display can cause inconsistency in the
- readings,&nbsp; and leading to poor results.<span
- style="font-weight: bold;"></span> LCD displays seem to be less
- influenced by what else is on the screen.<br>
- <br>
- If <span style="font-weight: bold;">dispcal</span> is run without
- arguments, it will provide a usage screen. The <span
- style="font-weight: bold;">-c</span> parameter allows selecting a
- communication port for an instrument, or selecting the instrument
- you want to use,&nbsp; and the <a href="dispcal.html#d"><span
- style="font-weight: bold;">-d</span></a> option allows selecting
- a target display on a multi-display system. On some multi-monitor
- systems, it may not be possible to independently calibrate and
- profile each display if they appear as one single screen to the
- operating system, or if it is not possible to set separate video
- lookup tables for each display. You can change the position and size
- of the test window using the <a href="dispcal.html#P"><span
- style="font-weight: bold;">-P</span></a> parameter. You can
- determine how best to arrange the test window, as well as whether
- each display has separate video lookup capability, by experimenting
- with the <a href="dispwin.html">dispwin</a> tool. <br>
- <br>
- For a more detailed discussion on interactively adjusting the
- display controls using <span style="font-weight: bold;">dispcal</span>,
- see <a href="dispcal.html#Adjustment">dispcal-adjustment</a>. Once
- you have adjusted and calibrated your display, you can move on to
- the next step.<br>
- <br>
- When you have calibrated and profiled your display, you can keep it
- calibrated using the <a href="dispcal.html#u">dispcal -u</a>
- option.<br>
- <br>
- <h4><a name="PM1c"></a>Adjusting, calibrating and profiling in one
- step.</h4>
- If a simple matrix/shaper display profile is all that is desired, <span
- style="font-weight: bold;">dispcal</span> can be used to do this,
- permitting display adjustment, calibration and profiling all in one
- operation. This is done by using the <span style="font-weight:
- bold;"><span style="font-weight: bold;">dispcal </span>-o</span>
- flag:<br>
- <br>
- <a href="dispcal.html">dispcal</a> <a href="dispcal.html#v">-v</a>
- <a href="dispcal.html#o">-o</a> <a href="dispcal.html#p1">TargetA</a><br>
- <br>
- This will create both a TargetA.cal file, but also a TargetA.icm
- file. See <a href="dispcal.html#o">-o</a> and <a
- href="dispcal.html#O">-O</a> for other variations.<br>
- <br>
- For more flexibility in creating a display profile, the separate
- steps of creating characterization test values using <span
- style="font-weight: bold;">targen</span>, reading them from the
- display using <span style="font-weight: bold;">dispread</span>, and
- then creating a profile using <span style="font-weight: bold;">colprof</span>
- are used. The following steps illustrate this:<br>
- <h4><a name="PM2"></a>Profiling in several steps: Creating display
- test values</h4>
- If the <span style="font-weight: bold;">dispcal</span> has not been
- used to create a display profile at the same time as adjustment and
- calibration, then it can be used to create a suitable set of
- calibration curves as the first step, or the calibration step can be
- omitted, and the display cansimply be profiled.<br>
- <br>
- The first step in profiling any output device, is to create a set of
- device colorspace test values. The important parameters needed are:
- <br>
- <ul>
- <li>What colorspace does the device use ?</li>
- <li>How many test patches do I want to use ?</li>
- <li>What information do I already have about how the device
- behaves ?</li>
- </ul>
- For a display device, &nbsp;the colorspace will be RGB. The number
- of test patches will depend somewhat on what quality profile you
- want to make, what type of profile you want to make, and how long
- you are prepared to wait when testing the display.<br>
- At a minimum, a few hundred values are needed. A matrix/shaper type
- of profile can get by with fewer test values, while a LUT based
- profile will give better results if more test values are used. A
- typical number might be 200-600 or so values, while 1000-2000 is not
- an unreasonable number for a high quality characterization of a
- display.<br>
- <br>
- To assist the choice of test patch values, it can help to have a
- rough idea of how the device behaves. This could be in the form of
- an ICC profile of a similar device, or a lower quality, or previous
- profile for that particular device. If one were going to make a very
- high quality LUT based profile, then it might be worthwhile to make
- up a smaller, preliminary shaper/matrix profile using a few hundred
- test points, before embarking on testing the device with several
- thousand.<br>
- <br>
- Lets say that we ultimately want to make a profile for the device
- "DisplayA", the simplest approach is to make a set of test values
- that is independent of the characteristics of the particular device:<br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
- <a href="targen.html#p1">DisplayA</a><br>
- <br>
- If there is a preliminary or previous profile called "OldDisplay"
- available, and we want to try creating a "pre-conditioned" set of
- test values that will more efficiently sample the device response,
- then the following would achieve this:<br>
- <u><br>
- </u><a href="targen.html"> targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
- <a href="targen.html#c">-cOldDisplay.icm</a> <a
- href="targen.html#p1">DisplayA</a><br>
- <br>
- The output of <b>targen</b> will be the file DisplayA.ti1,
- containing the device space test values, as well as expected CIE
- values used for chart recognition purposes.<br>
- <br>
- <h4><a name="PM3"></a>Profiling in several steps: Taking readings
- from a display</h4>
- First it is necessary to connect your measurement instrument to your
- computer, and check which communication port it is connected to. In
- the following example, it is assumed that the instrument is
- connected to the default port 1, which is either the first USB
- instrument found, or serial port found. Invoking dispread so as to
- display the usage information (by using a flag -? or --) will list
- the identified serial and USB ports, and their labels.<br>
- <br>
- <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
- <a href="dispread.html#p1">DisplayA</a><br>
- <br>
- If we created a calibration for the display using <a
- href="dispcal.html">dispcal</a>, then we will want to use this
- when we take the display readings (e.g. TargetA.cal from the
- calibration example)..<br>
- <br>
- <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
- <a href="dispread.html#k">-k TargetA.cal</a> <a
- href="dispread.html#p1">DisplayA</a><br>
- <br>
- <b>dispread</b> will display a test window in the middle of the
- screen, and issue a series of instructions about placing the
- instrument on the display. You may need to make sure that the
- display cursor is not in the test window, and it may also be
- necessary to disable any screensaver before starting the process.
- Exactly the same facilities are provided to select alternate
- displays using the <span style="font-weight: bold;">-d</span>
- parameter, and an alternate location and size for the test window
- using the <span style="font-weight: bold;">-P</span> parameter as
- with <span style="font-weight: bold;">dispcal</span>.<br>
- <h4><a name="PM4"></a>Profiling in several steps: Creating a display
- profile</h4>
- There are two basic choices of profile type for a display, a
- shaper/matrix profile, or a LUT based profile. They have different
- tradeoffs. A shaper/matrix profile will work well on a well behaved
- display, that is one that behaves in an additive color manner, will
- give very smooth looking results, and needs fewer test points to
- create. A LUT based profile on the other hand, will model any
- display behaviour more accurately, and can accommodate gamut mapping
- and different intent tables. Often it can show some unevenness and
- contouring in the results though.<br>
- <br>
- To create a matrix/shaper profile, the following suffices:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#a">-as</a> <a href="colprof.html#p1">DisplayA</a><br>
- <br>
- For a LUT based profile, where gamut mapping is desired, then a
- source profile will need to be provided to define the source gamut.
- For instance, if the display profile was likely to be linked to a
- CMYK printing source profile, say "swop.icm" or "fogra39l.icm", then
- the following would suffice:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#S">-S</a><a href="colprof.html#S">
- fogra39l.icm</a> <a href="colprof.html#c">-cpp</a> <a
- href="colprof.html#d">-dmt</a> <a href="colprof.html#p1">DisplayA</a><br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the sample data and profile is behaving
- reasonably.<br>
- If a calibration file was used with <a href="dispread.html">dispread</a>,
- then it will be converted to a vcgt tag in the profile, so that the
- operating system or other system color tools load the lookup curves
- into the display hardware, when the profile is used.<br>
- <h4><a name="PM5"></a>Installing a display profile</h4>
- <a href="dispwin.html">dispwin</a> provides a convenient way of
- installing a profile as the default system profile for the chosen
- display:<br>
- <br>
- <a href="dispwin.html">dispwin</a> <a href="dispwin.html#I">-I</a>
- <a href="dispwin.html#p1">DisplayA.icm</a><br>
- <br>
- This also sets the display to the calibration contained in the
- profile. If you want to try out a calibration before installing the
- profile, using dispwin without the <span style="font-weight: bold;">-I</span>
- option will load a calibration (ICC profile or .cal file) into the
- current display.<br>
- <br>
- Some systems will automatically set the display to the calibration
- contained in the installed profile (ie. OS X), while on other
- systems (ie. MSWindows and Linux/X11) it is necessary to use some
- tool to do this. On MSWindows XP you could install the
- optional&nbsp; <span style="font-weight: bold;">Microsoft&nbsp;Color&nbsp;Control&nbsp;Panel&nbsp;Applet&nbsp;for&nbsp;Windows&nbsp;XP</span>
- available for download from Microsoft to do this, but&nbsp;<span
- style="font-weight: bold;">NOTE</span> however that it seems to
- have a <span style="font-weight: bold;">bug</span>, in that it
- sometimes associates the profiles with the <span
- style="font-weight: bold;">wrong monitor</span> entry. Other
- display calibration tools will often install a similar tool, so
- beware of there being multiple, competing programs. [ Commonly these
- will be in your Start-&gt;Programs-&gt;Startup folder. ]<br>
- On Microsoft Vista, you need to use dispwin -L or some other tool to
- load the installed profiles calibration at startup.<br>
- <br>
- To use dispwin to load the installed profiles calibration to the
- display, use<br>
- <br>
- <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a><br>
- <br>
- As per usual, you can select the appropriate display using the <a
- href="dispwin.html#d">-d</a> flag.<br>
- <br>
- This can be automated on MSWindows and X11/Linux by adding this
- command to an appropriate startup script.<br>
- More system specific details, including how to create such startup
- scripts are <a href="dispprofloc.html">here</a>. <br>
- <br>
- If you are using Microsoft <span style="font-weight: bold;">Vista</span>,
- there is a known <span style="font-weight: bold;">bug</span> in
- Vista that resets the calibration every time a fade-in effect is
- executed, which happens if you lock and unlock the computer, resume
- from sleep or hibernate, or User Access Control is activated. Using
- <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a>
- may not restore the calibration, because Vista filters out setting
- (what it thinks) is a calibration that is already loaded. Use <a
- href="dispwin.html">dispwin</a> <a href="dispwin.html#c">-c</a> <a
- href="dispwin.html#L">-L</a><span style="font-family: monospace;"></span>
- as a workaround, as this will first clear the calibration, then
- re-load the current calibration.<br>
- <br>
- On X11/Linux systems, you could try adding <a href="dispwin.html">dispwin</a>
- <a href="dispwin.html#L">-L</a> to your <span style="font-weight:
- bold;">~/.config/autostart</span> file, so that your window
- manager automatically sets calibration when it starts. If you are
- running XRandR 1.2, you might consider running the experimental <a
- href="dispwin.html#D">dispwin -E</a> in the background, as in its
- "daemon" mode it will update the profile and calibration in response
- to any changes in the the connected display.<br>
- <br>
- <h4><a name="PM6"></a>Expert tips when measuring displays:<br>
- </h4>
- Sometimes it can be difficult to get good quality, consistent and
- visually relevant readings from displays, due to various practical
- considerations with regard to instruments and the displays
- themselves. Argyll's tools have some extra options that may assist
- in overcoming these problems.<br>
- <br>
- If you are using an Eye-One Pro or ColorMunki spectrometer, then you
- may wish to use the <a href="dispcal.html#H">high resolution
- spectral mode</a> (<span style="font-weight: bold;">-H</span>).
- This may be better at capturing the often narrow wavelength peaks
- that are typical of display primary colors.<br>
- <br>
- All instruments depend on silicon sensors, and such sensors generate
- a temperature dependant level of noise ("dark noise") that is
- factored out of the measurements by a dark or black instrument
- calibration. The spectrometers in particular need this calibration
- before commencing each set of measurements. Often an instrument will
- warm up as it sits on a display, and this warming up can cause the
- dark noise to increase, leading to inaccuracies in dark patch
- measurements. The longer the measurement takes, the worse this
- problem is likely to be. One way of addressing this is to
- "acclimatise" the instrument before commencing measurements by
- placing it on the screen in a powered up state, and leaving it for
- some time. (Some people leave it for up to an hour to acclimatise.).
- Another approach is to try and <a href="dispcal.html#I">compensate
- for dark calibration changes</a> (<span style="font-weight: bold;">-Ib</span>)
- by doing on the fly calibrations during the measurements, based on
- the assumption that the black level of the display itself won't
- change significantly. <br>
- <br>
- Some displays take a long time to settle down and stabilise. The is
- often the case with LCD (Liquid Crystal) displays that use
- fluorescent back lights, and these sorts of displays can change in
- brightness significantly with changes in temperature. One way of
- addressing this is to make sure that the display is given adequate
- time to warm up before measurements. Another approach is to try and
+
+
+
+ -r</span> for an LCD display, or <span style="text-decoration:
+ underline; color: rgb(204, 51, 204);">dispcal -yc -r</span> for a
+ CRT display with most of the colorimeter instruments. If so, this
+ will apply to all of the following examples.)<br>
+ <br>
+ Once this is done, <a href="dispcal.html">dispcal</a> can be run to
+ guide you through the display adjustments, and then calibrate it. By
+ default, the brightness and white point will be kept the same as the
+ devices natural brightness and white point. The default response
+ curve is a gamma of 2.4, except for Apple OS X systems prior to 10.6
+ where a gamma of 1.8 is the default. 2.4 is close to that of&nbsp;
+ many monitors, and close to that of the sRGB colorspace. <br>
+ <br>
+ A typical calibration that leaves the brightness and white point
+ alone, might be:<br>
+ <br>
+ <a href="dispcal.html">dispcal</a> -v TargetA<br>
+ <br>
+ which will result in a "TargetA.cal" calibration file, that can then
+ be used during the profiling stage.<br>
+ <br>
+ If the absolutely native response of the display is desired during
+ profiling, then calibration should be skipped, and the linear.cal
+ file from the "ref" directory used instead as the argument to the -k
+ flag of <span style="font-weight: bold;">dispread</span>.<br>
+ <br>
+ <b>Dispcal</b> will display a test window in the middle of the
+ screen, and issue a series of instructions about placing the
+ instrument on the display. You may need to make sure that the
+ display cursor is not in the test window, and it may also be
+ necessary to disable any screensaver and powersavers before starting
+ the process, although both <span style="font-weight: bold;">dispcal</span>
+ and <span style="font-weight: bold;">dispread</span> will attempt
+ to do this for you. It's also highly desirable on CRT's, to clear
+ your screen of any white or bright background images or windows
+ (running your shell window with white text on a black background
+ helps a lot here.), or at least keep any bright areas away from the
+ test window, and be careful not to change anything on the display
+ while the readings are taken. Lots of bright images or windows can
+ affect the ability to measure the black point accurately, and
+ changing images on the display can cause inconsistency in the
+ readings,&nbsp; and leading to poor results.<span
+ style="font-weight: bold;"></span> LCD displays seem to be less
+ influenced by what else is on the screen.<br>
+ <br>
+ If <span style="font-weight: bold;">dispcal</span> is run without
+ arguments, it will provide a usage screen. The <span
+ style="font-weight: bold;">-c</span> parameter allows selecting a
+ communication port for an instrument, or selecting the instrument
+ you want to use,&nbsp; and the <a href="dispcal.html#d"><span
+ style="font-weight: bold;">-d</span></a> option allows selecting
+ a target display on a multi-display system. On some multi-monitor
+ systems, it may not be possible to independently calibrate and
+ profile each display if they appear as one single screen to the
+ operating system, or if it is not possible to set separate video
+ lookup tables for each display. You can change the position and size
+ of the test window using the <a href="dispcal.html#P"><span
+ style="font-weight: bold;">-P</span></a> parameter. You can
+ determine how best to arrange the test window, as well as whether
+ each display has separate video lookup capability, by experimenting
+ with the <a href="dispwin.html">dispwin</a> tool. <br>
+ <br>
+ For a more detailed discussion on interactively adjusting the
+ display controls using <span style="font-weight: bold;">dispcal</span>,
+ see <a href="dispcal.html#Adjustment">dispcal-adjustment</a>. Once
+ you have adjusted and calibrated your display, you can move on to
+ the next step.<br>
+ <br>
+ When you have calibrated and profiled your display, you can keep it
+ calibrated using the <a href="dispcal.html#u">dispcal -u</a>
+ option.<br>
+ <br>
+ <h4><a name="PM1c"></a>Adjusting, calibrating and profiling in one
+ step.</h4>
+ If a simple matrix/shaper display profile is all that is desired, <span
+ style="font-weight: bold;">dispcal</span> can be used to do this,
+ permitting display adjustment, calibration and profiling all in one
+ operation. This is done by using the <span style="font-weight:
+ bold;"><span style="font-weight: bold;">dispcal </span>-o</span>
+ flag:<br>
+ <br>
+ <a href="dispcal.html">dispcal</a> <a href="dispcal.html#v">-v</a>
+ <a href="dispcal.html#o">-o</a> <a href="dispcal.html#p1">TargetA</a><br>
+ <br>
+ This will create both a TargetA.cal file, but also a TargetA.icm
+ file. See <a href="dispcal.html#o">-o</a> and <a
+ href="dispcal.html#O">-O</a> for other variations.<br>
+ <br>
+ For more flexibility in creating a display profile, the separate
+ steps of creating characterization test values using <span
+ style="font-weight: bold;">targen</span>, reading them from the
+ display using <span style="font-weight: bold;">dispread</span>, and
+ then creating a profile using <span style="font-weight: bold;">colprof</span>
+ are used. The following steps illustrate this:<br>
+ <h4><a name="PM2"></a>Profiling in several steps: Creating display
+ test values</h4>
+ If the <span style="font-weight: bold;">dispcal</span> has not been
+ used to create a display profile at the same time as adjustment and
+ calibration, then it can be used to create a suitable set of
+ calibration curves as the first step, or the calibration step can be
+ omitted, and the display cansimply be profiled.<br>
+ <br>
+ The first step in profiling any output device, is to create a set of
+ device colorspace test values. The important parameters needed are:
+ <br>
+ <ul>
+ <li>What colorspace does the device use ?</li>
+ <li>How many test patches do I want to use ?</li>
+ <li>What information do I already have about how the device
+ behaves ?</li>
+ </ul>
+ For a display device, &nbsp;the colorspace will be RGB. The number
+ of test patches will depend somewhat on what quality profile you
+ want to make, what type of profile you want to make, and how long
+ you are prepared to wait when testing the display.<br>
+ At a minimum, a few hundred values are needed. A matrix/shaper type
+ of profile can get by with fewer test values, while a LUT based
+ profile will give better results if more test values are used. A
+ typical number might be 200-600 or so values, while 1000-2000 is not
+ an unreasonable number for a high quality characterization of a
+ display.<br>
+ <br>
+ To assist the choice of test patch values, it can help to have a
+ rough idea of how the device behaves. This could be in the form of
+ an ICC profile of a similar device, or a lower quality, or previous
+ profile for that particular device. If one were going to make a very
+ high quality LUT based profile, then it might be worthwhile to make
+ up a smaller, preliminary shaper/matrix profile using a few hundred
+ test points, before embarking on testing the device with several
+ thousand.<br>
+ <br>
+ Lets say that we ultimately want to make a profile for the device
+ "DisplayA", the simplest approach is to make a set of test values
+ that is independent of the characteristics of the particular device:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
+ <a href="targen.html#p1">DisplayA</a><br>
+ <br>
+ If there is a preliminary or previous profile called "OldDisplay"
+ available, and we want to try creating a "pre-conditioned" set of
+ test values that will more efficiently sample the device response,
+ then the following would achieve this:<br>
+ <u><br>
+ </u><a href="targen.html"> targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
+ <a href="targen.html#c">-cOldDisplay.icm</a> <a
+ href="targen.html#p1">DisplayA</a><br>
+ <br>
+ The output of <b>targen</b> will be the file DisplayA.ti1,
+ containing the device space test values, as well as expected CIE
+ values used for chart recognition purposes.<br>
+ <br>
+ <h4><a name="PM3"></a>Profiling in several steps: Taking readings
+ from a display</h4>
+ First it is necessary to connect your measurement instrument to your
+ computer, and check which communication port it is connected to. In
+ the following example, it is assumed that the instrument is
+ connected to the default port 1, which is either the first USB
+ instrument found, or serial port found. Invoking dispread so as to
+ display the usage information (by using a flag -? or --) will list
+ the identified serial and USB ports, and their labels.<br>
+ <br>
+ <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#p1">DisplayA</a><br>
+ <br>
+ If we created a calibration for the display using <a
+ href="dispcal.html">dispcal</a>, then we will want to use this
+ when we take the display readings (e.g. TargetA.cal from the
+ calibration example)..<br>
+ <br>
+ <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#k">-k TargetA.cal</a> <a
+ href="dispread.html#p1">DisplayA</a><br>
+ <br>
+ <b>dispread</b> will display a test window in the middle of the
+ screen, and issue a series of instructions about placing the
+ instrument on the display. You may need to make sure that the
+ display cursor is not in the test window, and it may also be
+ necessary to disable any screensaver before starting the process.
+ Exactly the same facilities are provided to select alternate
+ displays using the <span style="font-weight: bold;">-d</span>
+ parameter, and an alternate location and size for the test window
+ using the <span style="font-weight: bold;">-P</span> parameter as
+ with <span style="font-weight: bold;">dispcal</span>.<br>
+ <h4><a name="PM4"></a>Profiling in several steps: Creating a display
+ profile</h4>
+ There are two basic choices of profile type for a display, a
+ shaper/matrix profile, or a LUT based profile. They have different
+ tradeoffs. A shaper/matrix profile will work well on a well behaved
+ display, that is one that behaves in an additive color manner, will
+ give very smooth looking results, and needs fewer test points to
+ create. A LUT based profile on the other hand, will model any
+ display behaviour more accurately, and can accommodate gamut mapping
+ and different intent tables. Often it can show some unevenness and
+ contouring in the results though.<br>
+ <br>
+ To create a matrix/shaper profile, the following suffices:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-as</a> <a href="colprof.html#p1">DisplayA</a><br>
+ <br>
+ For a LUT based profile, where gamut mapping is desired, then a
+ source profile will need to be provided to define the source gamut.
+ For instance, if the display profile was likely to be linked to a
+ CMYK printing source profile, say "swop.icm" or "fogra39l.icm", then
+ the following would suffice:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S">
+ fogra39l.icm</a> <a href="colprof.html#c">-cpp</a> <a
+ href="colprof.html#d">-dmt</a> <a href="colprof.html#p1">DisplayA</a><br>
+ <br>
+ A fallback to using a specific source profile/gamut is to use a
+ general compression percentage as a gamut mapping:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="file:///D:/src/argyll/doc/colprof.html#S">-S</a><a
+ href="colprof.html#S"> 20</a> <a href="colprof.html#c">-cpp</a> <a
+ href="colprof.html#d">-dmt</a> <a href="colprof.html#p1">DisplayA</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the sample data and profile is behaving
+ reasonably.<br>
+ If a calibration file was used with <a href="dispread.html">dispread</a>,
+ then it will be converted to a vcgt tag in the profile, so that the
+ operating system or other system color tools load the lookup curves
+ into the display hardware, when the profile is used.<br>
+ <h4><a name="PM5"></a>Installing a display profile</h4>
+ <a href="dispwin.html">dispwin</a> provides a convenient way of
+ installing a profile as the default system profile for the chosen
+ display:<br>
+ <br>
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#I">-I</a>
+ <a href="dispwin.html#p1">DisplayA.icm</a><br>
+ <br>
+ This also sets the display to the calibration contained in the
+ profile. If you want to try out a calibration before installing the
+ profile, using dispwin without the <span style="font-weight: bold;">-I</span>
+ option will load a calibration (ICC profile or .cal file) into the
+ current display.<br>
+ <br>
+ Some systems will automatically set the display to the calibration
+ contained in the installed profile (ie. OS X), while on other
+ systems (ie. MSWindows and Linux/X11) it is necessary to use some
+ tool to do this. On MSWindows XP you could install the
+ optional&nbsp; <span style="font-weight: bold;">Microsoft&nbsp;Color&nbsp;Control&nbsp;Panel&nbsp;Applet&nbsp;for&nbsp;Windows&nbsp;XP</span>
+ available for download from Microsoft to do this, but&nbsp;<span
+ style="font-weight: bold;">NOTE</span> however that it seems to
+ have a <span style="font-weight: bold;">bug</span>, in that it
+ sometimes associates the profiles with the <span
+ style="font-weight: bold;">wrong monitor</span> entry. Other
+ display calibration tools will often install a similar tool, so
+ beware of there being multiple, competing programs. [ Commonly these
+ will be in your Start-&gt;Programs-&gt;Startup folder. ]<br>
+ On Microsoft Vista, you need to use dispwin -L or some other tool to
+ load the installed profiles calibration at startup.<br>
+ <br>
+ To use dispwin to load the installed profiles calibration to the
+ display, use<br>
+ <br>
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a><br>
+ <br>
+ As per usual, you can select the appropriate display using the <a
+ href="dispwin.html#d">-d</a> flag.<br>
+ <br>
+ This can be automated on MSWindows and X11/Linux by adding this
+ command to an appropriate startup script.<br>
+ More system specific details, including how to create such startup
+ scripts are <a href="dispprofloc.html">here</a>. <br>
+ <br>
+ If you are using Microsoft <span style="font-weight: bold;">Vista</span>,
+ there is a known <span style="font-weight: bold;">bug</span> in
+ Vista that resets the calibration every time a fade-in effect is
+ executed, which happens if you lock and unlock the computer, resume
+ from sleep or hibernate, or User Access Control is activated. Using
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a>
+ may not restore the calibration, because Vista filters out setting
+ (what it thinks) is a calibration that is already loaded. Use <a
+ href="dispwin.html">dispwin</a> <a href="dispwin.html#c">-c</a> <a
+ href="dispwin.html#L">-L</a><span style="font-family: monospace;"></span>
+ as a workaround, as this will first clear the calibration, then
+ re-load the current calibration.<br>
+ <br>
+ On X11/Linux systems, you could try adding <a href="dispwin.html">dispwin</a>
+ <a href="dispwin.html#L">-L</a> to your <span style="font-weight:
+ bold;">~/.config/autostart</span> file, so that your window
+ manager automatically sets calibration when it starts. If you are
+ running XRandR 1.2, you might consider running the experimental <a
+ href="dispwin.html#D">dispwin -E</a> in the background, as in its
+ "daemon" mode it will update the profile and calibration in response
+ to any changes in the the connected display.<br>
+ <br>
+ <h4><a name="PM6"></a>Expert tips when measuring displays:<br>
+ </h4>
+ Sometimes it can be difficult to get good quality, consistent and
+ visually relevant readings from displays, due to various practical
+ considerations with regard to instruments and the displays
+ themselves. Argyll's tools have some extra options that may assist
+ in overcoming these problems.<br>
+ <br>
+ If you are using an Eye-One Pro or ColorMunki spectrometer, then you
+ may wish to use the <a href="dispcal.html#H">high resolution
+ spectral mode</a> (<span style="font-weight: bold;">-H</span>).
+ This may be better at capturing the often narrow wavelength peaks
+ that are typical of display primary colors.<br>
+ <br>
+ All instruments depend on silicon sensors, and such sensors generate
+ a temperature dependant level of noise ("dark noise") that is
+ factored out of the measurements by a dark or black instrument
+ calibration. The spectrometers in particular need this calibration
+ before commencing each set of measurements. Often an instrument will
+ warm up as it sits on a display, and this warming up can cause the
+ dark noise to increase, leading to inaccuracies in dark patch
+ measurements. The longer the measurement takes, the worse this
+ problem is likely to be. One way of addressing this is to
+ "acclimatise" the instrument before commencing measurements by
+ placing it on the screen in a powered up state, and leaving it for
+ some time. (Some people leave it for up to an hour to acclimatise.).
+ Another approach is to try and <a href="dispcal.html#I">compensate
+ for dark calibration changes</a> (<span style="font-weight: bold;">-Ib</span>)
+ by doing on the fly calibrations during the measurements, based on
+ the assumption that the black level of the display itself won't
+ change significantly. <br>
+ <br>
+ Some displays take a long time to settle down and stabilise. The is
+ often the case with LCD (Liquid Crystal) displays that use
+ fluorescent back lights, and these sorts of displays can change in
+ brightness significantly with changes in temperature. One way of
+ addressing this is to make sure that the display is given adequate
+ time to warm up before measurements. Another approach is to try and
<a href="dispcal.html#I">compensate for display white level</a>&nbsp;
@@ -650,20 +665,23 @@
- (<span style="font-weight: bold;">-Iw</span>) changes by doing on
- the fly calibrations during the measurements. Instrument black level
- drift and display white level drift can be combined (<span
- style="font-weight: bold;">-Ibw</span>).<br>
- <br>
- Colorimeter instruments make use of physical color filters that
- approximate the standard observer spectral sensitivity curves.
- Because these filters are not perfectly accurate, the manufacturer
- calibrates the instrument for typical displays, which is why you
- have to make a selection between CRT (Cathode Ray Tube) and LCD
- (Liquid Crystal Display) modes. If you are measuring a display that
- has primary colorants that differ significantly from those typical
- displays,&nbsp; (ie. you have a Wide Gamut Display), then you may
- get disappointing results with a Colorimeter. One way of addressing
+
+
+
+ (<span style="font-weight: bold;">-Iw</span>) changes by doing on
+ the fly calibrations during the measurements. Instrument black level
+ drift and display white level drift can be combined (<span
+ style="font-weight: bold;">-Ibw</span>).<br>
+ <br>
+ Colorimeter instruments make use of physical color filters that
+ approximate the standard observer spectral sensitivity curves.
+ Because these filters are not perfectly accurate, the manufacturer
+ calibrates the instrument for typical displays, which is why you
+ have to make a selection between CRT (Cathode Ray Tube) and LCD
+ (Liquid Crystal Display) modes. If you are measuring a display that
+ has primary colorants that differ significantly from those typical
+ displays,&nbsp; (ie. you have a Wide Gamut Display), then you may
+ get disappointing results with a Colorimeter. One way of addressing
this problem is to use a <a href="File_Formats.html#.ccmx">Colorimeter
@@ -723,117 +741,120 @@
- Correction Matrix</a>. These are specific to a particular
- Colorimeter and Display make and model combination, although a
- matrix for a different but similar type of display may give better
- results than none at all. A list of contributed <span
- style="font-weight: bold;">ccmx</span> files is <a
- href="ccmxs.html">here</a>.<br>
- <br>
- <h4><a name="PM7"></a>Calibrating and profiling a display that
- doesn't have VideoLUT access.</h4>
- <p>In some situation there is no access to a displays VideoLUT
- hardware, and this hardware is what is usually used to implement
- display calibration. This could be because the display is being
- accessed via a web server, or because the driver or windowing
- system doesn't support VideoLUT access.<br>
- </p>
- <p>There are two basic options in this situation:<br>
- </p>
- <p>&nbsp; 1) Don't attempt to calibrate, just profile the display.<br>
- &nbsp; 2) Calibrate, but incorporate the calibration in some other
- way in the workflow.<br>
- </p>
- <p>The first case requires nothing special - just skip calibration
- (see the previous section <a href="#PM7">Profiling in several
- steps: Creating display test values</a>).</p>
- <p> In the second case, there are three choices:<br>
- </p>
- <p>&nbsp;2a) Use dispcal to create a calibration and a quick profile
- that incorporates the calibration into the profile.<br>
- &nbsp;2b) Use dispcal to create the calibration, then dispread and
- colprof to create a profile, and then incorporate the calibration
- into the profile using applycal.<br>
- &nbsp;2c) Use dispcal to create the calibration, then dispread and
- colprof to create a profile, and then apply the calibration after
- the profile in a cctiff workflow.<br>
- </p>
- <p>The first case requires nothing special, use dispcal in a normal
- fashioned with the <span style="font-weight: bold;">-o</span>
- option to generate a quick profile.The profile created will <span
- style="text-decoration: underline;">not</span> contain a 'vcgt'
- tag, but instead will have the calibration curves incorporated
- into the profile itself. If calibration parameters are chosen that
- change the displays white point or brightness, then this will
- result in a slightly unusual profile that has a white point that
- does not correspond with device R=G=B=1.0. Some systems may not
- cope properly with this type of profile, and a general shift in
- white point through such a profile can create an odd looking
- display if it is applied to images but not to other elements on
- the display say as GUI decoration elements or other application
- windows.<br>
- </p>
- <p>In the second case, the calibration file created using dispcal
- should be provided to dispread using the <span
- style="font-weight: bold;">-K</span> flag:<br>
- </p>
- <p><a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
- <a href="dispread.html#K">-K TargetA.cal</a> <a
- href="dispread.html#p1">DisplayA</a></p>
- <p><span style="font-weight: bold;"></span>Create the profile as
- usual using colprof. but note that colprof will ignore the
- calibration, and that no 'vcgt' tag will be added to the profile.<br>
- You can then use <a href="applycal.html">applycal </a>to combine
- the calibration into the profile. Note that the resulting profile
- will be slightly unusual, since the profile is not made completely
- consistent with the effects of the calibration, and the device
- R=G=B=1.0 probably not longer corresponds with the PCS white or
- the white point.<br>
- </p>
- In the third case, the same procedure as above is used to create a
- profile, but the calibration is applied in a raster transformation
- workflow explicitly, e.g.:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
- href="cctiff.html#p1">SourceProfile.icm</a> <a
- href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
- <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
- or<br>
- &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
- href="cctiff.html#p1">SourceProfile.icm</a> <a
- href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
- <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
- <span style="font-weight: bold;"></span><br>
- <hr size="2" width="100%">
- <h3><a name="PS1"></a>Profiling Scanners and other input devices
- such as cameras<br>
- </h3>
- Because a scanner or camera is an input device, it is necessary to
- go about profiling it in quite a different way to an output device.
- To profile it, a test chart is needed to exercise the input device
- response, to which the CIE values for each test patch is known.
- Generally standard reflection or transparency test charts are used
- for this purpose.<br>
- <h4><a name="PS2"></a>Types of test charts</h4>
- The most common and popular test chart for scanner profiling is the
- IT8.7/2 chart. This is a standard format chart generally reproduced
- on photographic film, containing about 264 test patches.<br>
- An accessible and affordable source of such targets is Wolf Faust a
- <a href="http://www.targets.coloraid.de/">www.coloraid.de</a>.<br>
- Another source is LaserSoft <a
- href="http://www.silverfast.com/show/it8/en.html">www.silverfast.com.</a><br>
- The Kodak Q-60 Color Input Target is also a typical example:<br>
- <br>
- <img src="Q60.jpg" alt="Kodak Q60 chart image" width="200"
- height="141"> <br>
- <br>
- A very simple chart that is widely available is the Macbeth
- ColorChecker chart, although it contains only 24 patches and
- therefore is probably not ideal for creating profiles:<br>
- <img alt="ColorChecker 24 patch" src="colorchecker.jpg"
- style="width: 112px; height: 78px;"><br>
- <br>
- Other popular charts are the X-Rite/GretagMacbeth ColorChecker DC
+
+
+
+ Correction Matrix</a>. These are specific to a particular
+ Colorimeter and Display make and model combination, although a
+ matrix for a different but similar type of display may give better
+ results than none at all. A list of contributed <span
+ style="font-weight: bold;">ccmx</span> files is <a
+ href="ccmxs.html">here</a>.<br>
+ <br>
+ <h4><a name="PM7"></a>Calibrating and profiling a display that
+ doesn't have VideoLUT access.</h4>
+ <p>In some situation there is no access to a displays VideoLUT
+ hardware, and this hardware is what is usually used to implement
+ display calibration. This could be because the display is being
+ accessed via a web server, or because the driver or windowing
+ system doesn't support VideoLUT access.<br>
+ </p>
+ <p>There are two basic options in this situation:<br>
+ </p>
+ <p>&nbsp; 1) Don't attempt to calibrate, just profile the display.<br>
+ &nbsp; 2) Calibrate, but incorporate the calibration in some other
+ way in the workflow.<br>
+ </p>
+ <p>The first case requires nothing special - just skip calibration
+ (see the previous section <a href="#PM7">Profiling in several
+ steps: Creating display test values</a>).</p>
+ <p> In the second case, there are three choices:<br>
+ </p>
+ <p>&nbsp;2a) Use dispcal to create a calibration and a quick profile
+ that incorporates the calibration into the profile.<br>
+ &nbsp;2b) Use dispcal to create the calibration, then dispread and
+ colprof to create a profile, and then incorporate the calibration
+ into the profile using applycal.<br>
+ &nbsp;2c) Use dispcal to create the calibration, then dispread and
+ colprof to create a profile, and then apply the calibration after
+ the profile in a cctiff workflow.<br>
+ </p>
+ <p>The first case requires nothing special, use dispcal in a normal
+ fashioned with the <span style="font-weight: bold;">-o</span>
+ option to generate a quick profile.The profile created will <span
+ style="text-decoration: underline;">not</span> contain a 'vcgt'
+ tag, but instead will have the calibration curves incorporated
+ into the profile itself. If calibration parameters are chosen that
+ change the displays white point or brightness, then this will
+ result in a slightly unusual profile that has a white point that
+ does not correspond with device R=G=B=1.0. Some systems may not
+ cope properly with this type of profile, and a general shift in
+ white point through such a profile can create an odd looking
+ display if it is applied to images but not to other elements on
+ the display say as GUI decoration elements or other application
+ windows.<br>
+ </p>
+ <p>In the second case, the calibration file created using dispcal
+ should be provided to dispread using the <span
+ style="font-weight: bold;">-K</span> flag:<br>
+ </p>
+ <p><a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#K">-K TargetA.cal</a> <a
+ href="dispread.html#p1">DisplayA</a></p>
+ <p><span style="font-weight: bold;"></span>Create the profile as
+ usual using colprof. but note that colprof will ignore the
+ calibration, and that no 'vcgt' tag will be added to the profile.<br>
+ You can then use <a href="applycal.html">applycal </a>to combine
+ the calibration into the profile. Note that the resulting profile
+ will be slightly unusual, since the profile is not made completely
+ consistent with the effects of the calibration, and the device
+ R=G=B=1.0 probably not longer corresponds with the PCS white or
+ the white point.<br>
+ </p>
+ In the third case, the same procedure as above is used to create a
+ profile, but the calibration is applied in a raster transformation
+ workflow explicitly, e.g.:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">SourceProfile.icm</a> <a
+ href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">SourceProfile.icm</a> <a
+ href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <span style="font-weight: bold;"></span><br>
+ <hr size="2" width="100%">
+ <h3><a name="PS1"></a>Profiling Scanners and other input devices
+ such as cameras<br>
+ </h3>
+ Because a scanner or camera is an input device, it is necessary to
+ go about profiling it in quite a different way to an output device.
+ To profile it, a test chart is needed to exercise the input device
+ response, to which the CIE values for each test patch is known.
+ Generally standard reflection or transparency test charts are used
+ for this purpose.<br>
+ <h4><a name="PS2"></a>Types of test charts</h4>
+ The most common and popular test chart for scanner profiling is the
+ IT8.7/2 chart. This is a standard format chart generally reproduced
+ on photographic film, containing about 264 test patches.<br>
+ An accessible and affordable source of such targets is Wolf Faust a
+ <a href="http://www.targets.coloraid.de/">www.coloraid.de</a>.<br>
+ Another source is LaserSoft <a
+ href="http://www.silverfast.com/show/it8/en.html">www.silverfast.com.</a><br>
+ The Kodak Q-60 Color Input Target is also a typical example:<br>
+ <br>
+ <img src="Q60.jpg" alt="Kodak Q60 chart image" width="200"
+ height="141"> <br>
+ <br>
+ A very simple chart that is widely available is the Macbeth
+ ColorChecker chart, although it contains only 24 patches and
+ therefore is probably not ideal for creating profiles:<br>
+ <img alt="ColorChecker 24 patch" src="colorchecker.jpg"
+ style="width: 112px; height: 78px;"><br>
+ <br>
+ Other popular charts are the X-Rite/GretagMacbeth ColorChecker DC
and <a href="http://www.xrite.com/product_overview.aspx?ID=938">ColorChecker
@@ -894,17 +915,20 @@
- SG</a> charts:<br>
- <br>
- <img src="DC.jpg" alt="GretagMacbeth ColorChecker DC chart"
- width="200" height="122"> <img alt="ColorChecker SG" src="SG.jpg"
- style="width: 174px; height: 122px;"><br>
- <br>
- The GretagMacbeth Eye-One Pro Scan Target 1.4 can also be used:<br>
- <br>
- <img alt="Eye-One Scan Target 1.4" src="i1scan14.jpg" style="border:
- 2px solid ; width: 200px; height: 140px;"><br>
- <br>
+
+
+
+ SG</a> charts:<br>
+ <br>
+ <img src="DC.jpg" alt="GretagMacbeth ColorChecker DC chart"
+ width="200" height="122"> <img alt="ColorChecker SG" src="SG.jpg"
+ style="width: 174px; height: 122px;"><br>
+ <br>
+ The GretagMacbeth Eye-One Pro Scan Target 1.4 can also be used:<br>
+ <br>
+ <img alt="Eye-One Scan Target 1.4" src="i1scan14.jpg" style="border:
+ 2px solid ; width: 200px; height: 140px;"><br>
+ <br>
Also supported is the <a href="http://www.hutchcolor.com/hct.htm">HutchColor
@@ -965,22 +989,28 @@
- HCT</a> :<br>
- <br>
- <img alt="HutchColor HCT" src="HCT.jpg" style="width: 182px; height:
- 140px;"><br>
- <br>
- <br>
- and <a href="http://www.cmp-color.fr/DT3.html">Christophe
- Métairie's Digital TargeT 003</a> and <a
- href="http://www.cmp-color.fr/digital%20target.html">Christophe
- Métairie's Digital Target - 4</a> :<br>
- <br>
- <img alt="CMP_DT_003" src="CMP_DT_003.jpg" style="width: 186px;
- height: 141px;">&nbsp; <img style="width: 203px; height: 140px;"
- alt="CMP_Digital_Target-4" src="CMP_Digital_Target-4.jpg"
- width="203" height="140"><br>
- <br>
+
+
+
+ HCT</a> :<br>
+ <br>
+ <img alt="HutchColor HCT" src="HCT.jpg" style="width: 182px; height:
+ 140px;"><br>
+ <br>
+ <br>
+ and <a href="http://www.cmp-color.fr/DT3.html">Christophe
+ Métairie's Digital TargeT 003</a>, <a
+ href="http://www.cmp-color.fr/digital%20target.html">Christophe
+ Métairie's Digital Target - 4</a> , and <a
+ href="http://www.cmp-color.fr/digital%20target.html">Christophe
+ Métairie's Digital Target - 7</a>:<br>
+ <br>
+ <img alt="CMP_DT_003" src="CMP_DT_003.jpg" style="width: 186px;
+ height: 141px;">&nbsp; <img style="width: 203px; height: 140px;"
+ alt="CMP_Digital_Target-4" src="CMP_Digital_Target-4.jpg"
+ width="203" height="140">&nbsp; <img alt="CMP_Digital_Target-4"
+ src="CMP_Digital_Target-7.jpg" width="202" height="146"><br>
+ <br>
and the <a href="http://www.silverfast.com/show/dc-targets/en.html">LaserSoft
@@ -1041,25 +1071,28 @@
- Imaging DCPro Target</a>:<br>
- <br>
- <img style="width: 153px; height: 122px;" alt="LaserSoft DCPro
- Target" src="LSDC.jpg"><br>
- <br>
- The Datacolor <a
- href="http://spyder.datacolor.com/product-cb-spydercheckr.php">SpyderCheckr</a>:<br>
- <br>
- <img style=" width: 146px; height: 109px;" alt="Datacolor
- SpyderCheckr" src="SpyderChecker.jpg"><br>
- <br>
- The Datacolor <a
- href="http://spyder.datacolor.com/portfolio-view/spydercheckr-24/">SpyderCheckr24</a>:<br>
- <br>
- <img alt="SpyderCheckr24" src="SpyderChecker24.jpg" width="82"
- height="122"><br>
- <br>
- One of the QPcard's:<br>
- <a
+
+
+
+ Imaging DCPro Target</a>:<br>
+ <br>
+ <img style="width: 153px; height: 122px;" alt="LaserSoft DCPro
+ Target" src="LSDC.jpg"><br>
+ <br>
+ The Datacolor <a
+ href="http://spyder.datacolor.com/product-cb-spydercheckr.php">SpyderCheckr</a>:<br>
+ <br>
+ <img style=" width: 146px; height: 109px;" alt="Datacolor
+ SpyderCheckr" src="SpyderChecker.jpg"><br>
+ <br>
+ The Datacolor <a
+ href="http://spyder.datacolor.com/portfolio-view/spydercheckr-24/">SpyderCheckr24</a>:<br>
+ <br>
+ <img alt="SpyderCheckr24" src="SpyderChecker24.jpg" width="82"
+ height="122"><br>
+ <br>
+ One of the QPcard's:<br>
+ <a
href="http://www.qpcard.com/en_b2c/color-reference-cards/qpcard201.html">QPcard
@@ -1114,7 +1147,10 @@
- 201</a>:&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <a
+
+
+
+ 201</a>:&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <a
href="http://www.qpcard.com/en_b2c/color-reference-cards/instant-camera-raw-profiling-with-qpcard-202.html">QPcard
@@ -1169,86 +1205,89 @@ href="http://www.qpcard.com/en_b2c/color-reference-cards/instant-camera-raw-prof
- 202</a>:<br>
- <br>
- <img style=" width: 41px; height: 141px;" alt="QPCard201"
- src="QPcard201.jpg">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <img
- style=" width: 97px; height: 141px;" alt="QPcard202"
- src="QPcard202.jpg"><br>
- <br>
- <h4><a name="PS3"></a>Taking readings from a scanner or camera<br>
- </h4>
- The test chart you are using needs to be placed on the scanner, and
- the scanner needs to be configured to a suitable state, and restored
- to that same state when used subsequently with the resulting
- profile. For a camera, the chart needs to be lit in a controlled and
- even manner using the light source that will be used for subsequent
- photographs, and should be shot so as to minimise any geometric
- distortion, although the <a href="scanin.html#p">scanin -p</a> flag
- may be used to compensate for some degree of distortion. As with any
- color profiling task, it is important to setup a known and
- repeatable image processing flow, to ensure that the resulting
- profile will be usable.<br>
- <br>
- The chart should be captured and saved to a TIFF format file. I will
- assume the resulting file is called scanner.tif. The raster file
- need only be roughly cropped so as to contain the test chart
- (including the charts edges).<br>
- <br>
- The second step is to extract the RGB values from the scanner.tif
- file, and match then to the reference CIE values. To locate the
- patch values in the scan, the <b>scanin</b> tool needs to be given
- a template <a href="File_Formats.html#.cht">.cht</a> file that
- describes the features of the chart, and how the test patches are
- labeled. Also needed is a file containing the CIE values for each of
- the patches in the chart, which is typically supplied with the
- chart, available from the manufacturers web site, or has been
- measured using a spectrometer.<br>
- <br>
- <div style="margin-left: 40px;">For an IT8.7/2 chart, this is the <span
- style="font-weight: bold;">ref/</span><b>it8.cht</b> file
- supplied with Argyll, and&nbsp; the manufacturer will will supply
- an individual or batch average file along with the chart
- containing this information, or downloadable from their web site.
- For instance, Kodak Q60 target reference files are <a
- href="ftp://ftp.kodak.com/gastds/Q60DATA/">here</a>.<br>
- NOTE that the reference file for the IT8.7/2 chart supplied with <span
- style="font-weight: bold;">Monaco&nbsp;EZcolor</span> can be
- obtained by unzipping the .mrf file. (You may have to make a copy
- of the file with a .zip extension to do this.)<br>
- <br>
- For the ColorChecker 24 patch chart, the <span
- style="font-weight: bold;">ref/ColorChecker.cht</span> file
- should be used, and there is also a <span style="font-weight:
- bold;">ref/ColorChecker.cie</span> file provided that is based
- on the manufacturers reference values for the chart. You can also
- create your own reference file using an instrument and chartread,
- making use of the chart reference file <span style="font-weight:
- bold;">ref/ColorChecker.ti2</span>:<br>
- &nbsp;&nbsp; <a href="chartread.html">chartread</a> -n
- ColorChecker.ti2<br>
- Note that due to the small number of patches, a profile created
- from such a chart is not likely to be very detailed.<br>
- <br>
- For the ColorChecker DC chart, the <span style="font-weight:
- bold;">ref/ColorCheckerDC.cht</span> file should be used, and
- there will be a ColorCheckerDC reference file supplied by
- X-Rite/GretagMacbeth with the chart.<br>
- <br>
- The ColorChecker SG is relatively expensive, but is preferred by
- many people because (like the ColorChecker and ColorCheckerDC) its
- colors are composed of multiple different pigments, giving it
- reflective spectra that are more representative of the real world,
- unlike many other charts that are created out of combination of 3
- or 4 colorants.<br>
- A limited CIE reference file is available from X-Rite <a
-href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.txt">here</a>,
- but it is not in the usual CGATS format. To convert it to a CIE
- reference file useful for <span style="font-weight: bold;">scanin</span>,
- you will need to edit the X-Rite file using a <span
- style="text-decoration: underline;">plain text</span> editor,
- first deleting everything before the line starting with "A1" and
+
+
+
+ 202</a>:<br>
+ <br>
+ <img style=" width: 41px; height: 141px;" alt="QPCard201"
+ src="QPcard201.jpg">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <img
+ style=" width: 97px; height: 141px;" alt="QPcard202"
+ src="QPcard202.jpg"><br>
+ <br>
+ <h4><a name="PS3"></a>Taking readings from a scanner or camera<br>
+ </h4>
+ The test chart you are using needs to be placed on the scanner, and
+ the scanner needs to be configured to a suitable state, and restored
+ to that same state when used subsequently with the resulting
+ profile. For a camera, the chart needs to be lit in a controlled and
+ even manner using the light source that will be used for subsequent
+ photographs, and should be shot so as to minimise any geometric
+ distortion, although the <a href="scanin.html#p">scanin -p</a> flag
+ may be used to compensate for some degree of distortion. As with any
+ color profiling task, it is important to setup a known and
+ repeatable image processing flow, to ensure that the resulting
+ profile will be usable.<br>
+ <br>
+ The chart should be captured and saved to a TIFF format file. I will
+ assume the resulting file is called scanner.tif. The raster file
+ need only be roughly cropped so as to contain the test chart
+ (including the charts edges).<br>
+ <br>
+ The second step is to extract the RGB values from the scanner.tif
+ file, and match then to the reference CIE values. To locate the
+ patch values in the scan, the <b>scanin</b> tool needs to be given
+ a template <a href="File_Formats.html#.cht">.cht</a> file that
+ describes the features of the chart, and how the test patches are
+ labeled. Also needed is a file containing the CIE values for each of
+ the patches in the chart, which is typically supplied with the
+ chart, available from the manufacturers web site, or has been
+ measured using a spectrometer.<br>
+ <br>
+ <div style="margin-left: 40px;">For an IT8.7/2 chart, this is the <span
+ style="font-weight: bold;">ref/</span><b>it8.cht</b> file
+ supplied with Argyll, and&nbsp; the manufacturer will will supply
+ an individual or batch average file along with the chart
+ containing this information, or downloadable from their web site.
+ For instance, Kodak Q60 target reference files are <a
+ href="ftp://ftp.kodak.com/gastds/Q60DATA/">here</a>.<br>
+ NOTE that the reference file for the IT8.7/2 chart supplied with <span
+ style="font-weight: bold;">Monaco&nbsp;EZcolor</span> can be
+ obtained by unzipping the .mrf file. (You may have to make a copy
+ of the file with a .zip extension to do this.)<br>
+ <br>
+ For the ColorChecker 24 patch chart, the <span
+ style="font-weight: bold;">ref/ColorChecker.cht</span> file
+ should be used, and there is also a <span style="font-weight:
+ bold;">ref/ColorChecker.cie</span> file provided that is based
+ on the manufacturers reference values for the chart. You can also
+ create your own reference file using an instrument and chartread,
+ making use of the chart reference file <span style="font-weight:
+ bold;">ref/ColorChecker.ti2</span>:<br>
+ &nbsp;&nbsp; <a href="chartread.html">chartread</a> -n
+ ColorChecker.ti2<br>
+ Note that due to the small number of patches, a profile created
+ from such a chart is not likely to be very detailed.<br>
+ <br>
+ For the ColorChecker DC chart, the <span style="font-weight:
+ bold;">ref/ColorCheckerDC.cht</span> file should be used, and
+ there will be a ColorCheckerDC reference file supplied by
+ X-Rite/GretagMacbeth with the chart.<br>
+ <br>
+ The ColorChecker SG is relatively expensive, but is preferred by
+ many people because (like the ColorChecker and ColorCheckerDC) its
+ colors are composed of multiple different pigments, giving it
+ reflective spectra that are more representative of the real world,
+ unlike many other charts that are created out of combination of 3
+ or 4 colorants.<br>
+ A limited CIE reference file is available from X-Rite <a
+href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.txt">here</a>,
+ but it is not in the usual CGATS format. To convert it to a CIE
+ reference file useful for <span style="font-weight: bold;">scanin</span>,
+ you will need to edit the X-Rite file using a <span
+ style="text-decoration: underline;">plain text</span> editor,
+ first deleting everything before the line starting with "A1" and
everything after "N10", then prepending <a href="SG_header.txt">this
@@ -1308,92 +1347,108 @@ href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.t
- header</a>, and appending <a href="SG_footer.txt">this footer</a>,
- making sure there are no blank lines inserted in the process.
- There are reports that X-Rite have experimented with different ink
- formulations for certain patches, so the above reference may not
- be as accurate as desired, and it is preferable to measure your
- own chart using a spectrometer, if you have the capability.<br>
- If you do happen to have access to a more comprehensive instrument
- measurement of the ColorChecker SG, or you have measured it
- yourself using a color instrument,<br>
- then you <span style="text-decoration: underline;">may</span>
- need to convert the reference information from spectral <span
- style="font-weight: bold;">ColorCheckerSG.txt</span> file to CIE
- value <span style="font-weight: bold;">ColorCheckerSG.cie</span>
- reference file, follow the following steps:<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="txt2ti3.html">txt2ti3</a>
- ColorCheckerSG.txt ColorCheckerSG<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="spec2cie.html">spec2cie</a>
- ColorCheckerSG.ti3 ColorCheckerSG.cie<br>
- <br>
- For the Eye-One Pro Scan Target 1.4 chart, the <span
- style="font-weight: bold;"><span style="font-weight: bold;">ref/</span>i1_RGB_Scan_1.4.cht</span>
- file should be used, and as there is no reference file
- accompanying this chart, the chart needs to be read with an
- instrument (usually the Eye-One Pro). This can be done using
- chartread,&nbsp; making use of the chart reference file <span
- style="font-weight: bold;">ref/i1_RGB_Scan_1.4.ti2</span>:<br>
- &nbsp;&nbsp;&nbsp; <a href="chartread.html">chartread</a> -n
- i1_RGB_Scan_1.4<br>
- and then rename the resulting <span style="font-weight: bold;">i1_RGB_Scan_1.4.ti3</span>
- file to <span style="font-weight: bold;">i1_RGB_Scan_1.4.cie</span><br>
- <span style="font-weight: bold;"></span><br>
- For the HutchColor HCT chart, the <span style="font-weight:
- bold;"><span style="font-weight: bold;">ref/</span>Hutchcolor.cht</span>
- file should be used, and the reference <span style="font-weight:
- bold;">.txt</span> file downloaded from the HutchColor website.<br>
- <br>
- For the Christophe Métairie's Digital TargeT 003 chart with 285
- patches, the <span style="font-weight: bold;"><span
- style="font-weight: bold;">ref/</span>CMP_DT_003.cht</span>
- file should be used, and the cie reference <span
- style="font-weight: bold;"></span>files come with the chart.<br>
- <br>
- For the Christophe Métairie's Digital Target-4 chart with 570
- patches, the <span style="font-weight: bold;">ref/CMP_Digital_Target-4.cht</span>
- file should be used, and the cie reference <span
- style="font-weight: bold;"></span>files come with the chart.<br>
- <br>
- For the LaserSoft DCPro chart, the <span style="font-weight:
- bold;">ref/LaserSoftDCPro.cht</span> file should be used, and
- reference <span style="font-weight: bold;">.txt</span> file
- downloaded from the <a
- href="http://www.silverfast.com/it8calibration/">Silverfast
- website</a>.<br>
- <br>
- For the Datacolor SpyderCheckr, the <span style="font-weight:
- bold;">ref/SpyderChecker.cht</span> file should be used, and a
- reference <span style="font-weight: bold;">ref/SpyderChecker.cie
- </span>file made from measuring a sample chart is also available.
- Alternately you could create your own reference file by
- transcribing the <a
- href="http://spyder.datacolor.com/images/photo_checkr_colordatainfo.jpg">values</a>
- on the Datacolor website. <br>
- <br>
- For the Datacolor SpyderCheckr, the <span style="font-weight:
- bold;">ref/SpyderChecker24.cht</span> file should be used, and a
+
+
+
+ header</a>, and appending <a href="SG_footer.txt">this footer</a>,
+ making sure there are no blank lines inserted in the process. Name
+ the resulting file <b>ColorCheckerSG.cie</b>.<br>
+ There are reports that X-Rite have experimented with different ink
+ formulations for certain patches, so the above reference may not
+ be as accurate as desired, and it is preferable to measure your
+ own chart using a spectrometer, if you have the capability.<br>
+ If you do happen to have access to a more comprehensive instrument
+ measurement of the ColorChecker SG, or you have measured it
+ yourself using chart reading software other than ArgyllCMS, then
+ you <span style="text-decoration: underline;">may</span> need to
+ convert the reference information from spectral only <span
+ style="font-weight: bold;">ColorCheckerSG.txt</span> file to CIE
+ value <span style="font-weight: bold;">ColorCheckerSG.cie</span>
+ reference file, follow the following steps:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="txt2ti3.html">txt2ti3</a>
+ ColorCheckerSG.txt ColorCheckerSG<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="spec2cie.html">spec2cie</a>
+ ColorCheckerSG.ti3 ColorCheckerSG.cie<br>
+ <br>
+ For the Eye-One Pro Scan Target 1.4 chart, the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">ref/</span>i1_RGB_Scan_1.4.cht</span>
+ file should be used, and as there is no reference file
+ accompanying this chart, the chart needs to be read with an
+ instrument (usually the Eye-One Pro). This can be done using
+ chartread,&nbsp; making use of the chart reference file <span
+ style="font-weight: bold;">ref/i1_RGB_Scan_1.4.ti2</span>:<br>
+ &nbsp;&nbsp;&nbsp; <a href="chartread.html">chartread</a> -n
+ i1_RGB_Scan_1.4<br>
+ and then rename the resulting <span style="font-weight: bold;">i1_RGB_Scan_1.4.ti3</span>
+ file to <span style="font-weight: bold;">i1_RGB_Scan_1.4.cie</span><br>
+ <span style="font-weight: bold;"></span><br>
+ For the HutchColor HCT chart, the <span style="font-weight:
+ bold;"><span style="font-weight: bold;">ref/</span>Hutchcolor.cht</span>
+ file should be used, and the reference <span style="font-weight:
+ bold;">.txt</span> file downloaded from the HutchColor website.<br>
+ <br>
+ For the Christophe Métairie's Digital TargeT 003 chart with 285
+ patches, the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">ref/</span>CMP_DT_003.cht</span>
+ file should be used, and the cie reference <span
+ style="font-weight: bold;"></span>files come with the chart.<br>
+ <br>
+ For the Christophe Métairie's Digital Target-4 chart with 570
+ patches, the <span style="font-weight: bold;">ref/CMP_Digital_Target-4.cht</span>
+ file should be used, and the cie reference <span
+ style="font-weight: bold;"></span>files come with the chart.<br>
+ <br>
+ For the Christophe Métairie's Digital Target-7 chart with 570
+ patches, the <span style="font-weight: bold;">ref/CMP_Digital_Target-7.cht</span>
+ file should be used, and the spectral .txt file should be
+ converted to a cie reference file:<br>
+ &nbsp;&nbsp;&nbsp; <a href="txt2ti3.html">txt2ti3</a>
+ DT7_XXXXX_Spectral.txt temp<br>
+ &nbsp;&nbsp;&nbsp; <a href="spec2cie.html">spec2cie</a> temp.ti3
+ DT7_XXXXX.cie<br>
+ <br>
+ For the LaserSoft DCPro chart, the <span style="font-weight:
+ bold;">ref/LaserSoftDCPro.cht</span> file should be used, and
+ reference <span style="font-weight: bold;">.txt</span> file
+ downloaded from the <a
+ href="http://www.silverfast.com/it8calibration/">Silverfast
+ website</a>.<br>
+ <br>
+ For the Datacolor SpyderCheckr, the <span style="font-weight:
+ bold;">ref/SpyderChecker.cht</span> file should be used, and a
+ reference <span style="font-weight: bold;">ref/SpyderChecker.cie
+ </span>file made from measuring a sample chart is also available.
+ Alternately you could create your own reference file by
+ transcribing the <a
+ href="http://spyder.datacolor.com/images/photo_checkr_colordatainfo.jpg">values</a>
+ on the Datacolor website. <br>
+ <br>
+ For the Datacolor SpyderCheckr, the <span style="font-weight:
+ bold;">ref/SpyderChecker24.cht</span> file should be used, and a
reference <span style="font-weight: bold;">ref/SpyderChecker24.cie
- </span>file made from measuring a sample chart is also available.
- Alternately you could create your own reference file by
- transcribing the <a
- href="http://spyder.datacolor.com/images/photo_checkr_colordatainfo.jpg">values</a>
- on the Datacolor website. <br>
- <br>
- For the QPCard 201, the <span style="font-weight: bold;">ref/QPcard_201.cht</span>
- file should be used, and a reference <span style="font-weight:
- bold;">ref/QPcard_201.cie</span> file made from measuring a
- sample chart is also available. <br>
- <br>
- For the QPCard 202, the <span style="font-weight: bold;">ref/QPcard_202.cht</span>
- file should be used, and a reference <span style="font-weight:
- bold;">ref/QPcard_202.cie</span> file made from measuring a
- sample chart is also available. <br>
- </div>
- <br>
- For any other type of chart, a chart recognition template file will
- need to be created (this is beyond the scope of the current
+
+
+
+ </span>file made from measuring a sample chart is also available.
+ Alternately you could create your own reference file by
+ transcribing the <a
+ href="http://spyder.datacolor.com/images/photo_checkr_colordatainfo.jpg">values</a>
+ on the Datacolor website. <br>
+ <br>
+ For the QPCard 201, the <span style="font-weight: bold;">ref/QPcard_201.cht</span>
+ file should be used, and a reference <span style="font-weight:
+ bold;">ref/QPcard_201.cie</span> file made from measuring a
+ sample chart is also available. <br>
+ <br>
+ For the QPCard 202, the <span style="font-weight: bold;">ref/QPcard_202.cht</span>
+ file should be used, and a reference <span style="font-weight:
+ bold;">ref/QPcard_202.cie</span> file made from measuring a
+ sample chart is also available. <br>
+ </div>
+ <br>
+ For any other type of chart, a chart recognition template file will
+ need to be created (this is beyond the scope of the current
documentation, although see&nbsp; the <a href="cht_format.html">.cht_format
@@ -1453,402 +1508,405 @@ href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.t
- documentation</a>).<br>
- <br>
- To create the scanner .ti3 file, run the <b>scanin</b> tool as
- follows (assuming an IT8 chart is being used):<br>
- <br>
- <a href="scanin.html"> scanin</a> -v scanner.tif It8.cht It8ref.txt<br>
- <br>
- "It8ref.txt" or "It8ref.cie" is assumed to be the name of the CIE
- reference file supplied by the chart manufacturer. The resulting
- file will be named "<b>scanner.ti3</b>".<br>
- <br>
- <span style="font-weight: bold;">scanin</span> will process 16 bit
- per component .tiff files, which (if the scanner is capable of
- creating such files),&nbsp; may improve the quality of the profile.
- <br>
- <br>
- If you have any doubts about the correctness of the chart
- recognition, or the subsequent profile's delta E report is unusual,
- then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
- and examine the <span style="font-weight: bold;">diag.tif</span>
- diagnostic file, to make sure that the patches are identified and
- aligned correctly. If you have problems getting good automatic
- alignment, then consider doing a manual alignment by locating the
- fiducial marks on your scan, and feeding them into scanin <a
- href="scanin.html#F">-F</a> parameters. The fiducial marks should
- be listed in a clockwise direction starting at the top left.<br>
- <h4><a name="PS4"></a>Creating a scanner or camera input profile</h4>
- Similar to a display profile, an input profile can be either a
- shaper/matrix or LUT based profile. Well behaved input devices will
- probably give the best results with a shaper/matrix profile, and
- this may also be the best choice if your test chart has a small or
- unevenly distributed set of test patchs (ie. the IT8.7.2). If a
- shaper/matrix profile is a poor fit, consider using a LUT type
- profile.<br>
- <br>
- When creating a LUT type profile, there is the choice of XYZ or
- L*a*b* PCS (Device independent, Profile Connection Space). Often for
- input devices, it is better to choose the XYZ PCS, as this may be a
- better fit given that input devices are usually close to being
- linearly additive in behaviour.<br>
- <br>
- If the purpose of the input profile is to use it as a substitute for
- a colorimeter, then the <b>-u</b> flag should be used to avoid
- clipping values above the white point. Unless the shaper/matrix type
- profile is a very good fit, it is probably advisable to use a LUT
- type profile in this situation.<br>
- <br>
- To create a matrix/shaper profile, the following suffices:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Scanner</a> <a href="colprof.html#E">A"</a>
- <a href="colprof.html#q">-qm</a> <a href="colprof.html#a">-as</a> <a
- href="colprof.html#p1">scanner</a><br>
- <br>
- For an XYZ PCS LUT based profile then the following would be used:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#a">-ax</a> <a href="colprof.html#p1">scanner</a><br>
- <br>
- For the purposes of a poor mans colorimeter, the following would
- generally be used:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#a">-ax</a> <a href="colprof.html#u">-u</a> <a
- href="colprof.html#p1">scanner</a><br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the sample data and profile is behaving
- reasonably. Depending on the type of device, and the consistency of
- the readings, average errors of 5 or less, and maximum errors of 15
- or less would normally be expected. If errors are grossly higher
- than this, then this is an indication that something is seriously
- wrong with the device measurement, or profile creation.<br>
- <br>
- If profiling a <span style="font-weight: bold;">camera</span> in <span
- style="font-weight: bold;">RAW</span> mode, then there may be some
- advantage in creating a pure matrix only profile, in which it is
- assumed that the camera response is completely linear. This may
- reduce extrapolation artefacts. If setting the white point will be
- done in some application, then it may also be an advantage to use
- the <span style="font-weight: bold;">-u</span> flag and avoid
- setting the white point to that of the profile chart:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Camera"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#a">-am</a> <a href="colprof.html#u">-u</a> <a
- href="colprof.html#p1">scanner</a><br>
- <br>
- <br>
- <hr size="2" width="100%">
- <h3><a name="PP1"></a>Profiling Printers<br>
- </h3>
- The overall process is to create a set of device measurement target
- values, print them out, measure them, and then create an ICC profile
- from the measurements. If the printer is an RGB based printer, then
- the process is only slightly more complicated than profiling a
- display. If the printer is CMYK based, then some additional
- parameters are required to set the total ink limit (TAC) and
- &nbsp;black generation curve.<br>
- <h4><a name="PP2"></a>Creating a print profile test chart</h4>
- The first step in profiling any output device, is to create a set of
- device colorspace test values. The important parameters needed are:<br>
- <ul>
- <li>What colorspace does the device use ?</li>
- <li>How many test patches do I want to use/what paper size do I
- want to use ?</li>
- <li>What instrument am I going to use to read the patches ?<br>
- </li>
- <li>If it is a CMYK device, what is the total ink limit ?<br>
- </li>
- <li>What information do I already have about how the device
- behaves ?</li>
- </ul>
- Most printers running through simple drivers will appear as if they
- are RGB devices. In fact there is no such thing as a real RGB
- printer, since printers use white media and the colorant must
- subtract from the light reflected on it to create color, but the
- printer itself turns the incoming RGB into the native print
- colorspace, so for this reason we will tell targen to use the "Print
- RGB" colorspace, so that it knows that it's really a subtractive
- media. Other drivers will drive a printer more directly, and will
- expect a CMYK profile. [Currently Argyll is not capable of creating
- an ICC profile for devices with more colorants than CMYK. When this
- capability is introduced, it will by creating an additional
- separation profile which then allows the printer to be treated as a
- CMY or CMYK printer.] One way of telling what sort of profile is
- expected for your device is to examine an existing profile for that
- device using <a href="http://www.argyllcms.com/doc/iccdump.html">iccdump</a>.<br>
- <br>
- The number of test patches will depend somewhat on what quality
- profile you want to make, how well behaved the printer is, as well
- as the effort needed to read the number of test values. Generally it
- is convenient to fill a certain paper size with the maximum number
- of test values that will fit.<br>
- <br>
- At a minimum, for an "RGB" device, a few hundred values are needed
- (400-1000). For high quality CMYK profiles, 1000-3000 is not an
- unreasonable number of patches.<br>
- <br>
- To assist the determination of test patch values, it can help to
- have a rough idea of how the device behaves, so that the device test
- point locations can be pre-conditioned. This could be in the form of
- an ICC profile of a similar device, or a lower quality, or previous
- profile for that particular device. If one were going to make a very
- high quality Lut based profile, then it might be worthwhile to make
- up a smaller, preliminary shaper/matrix profile using a few hundred
- test points, before embarking on testing the device with several
- thousand.<br>
- <br>
- The documentation for the <a
- href="http://www.argyllcms.com/doc/targen.html">targen</a> tool
- lists a <a href="http://www.argyllcms.com/doc/targen.html#Table">table</a>
- of paper sizes and number of &nbsp;patches for typical situations.<br>
- <br>
- For a CMYK device, a total ink limit usually needs to be specified.
- Sometimes a device will have a maximum total ink limit set by its
- manufacturer or operator, and some CMYK systems (such as chemical
- proofing systems) don't have any limit. Typical printing devices
- such as Xerographic printers, inkjet printers and printing presses
- will have a limit. The exact procedure for determining an ink limit
- is outside the scope of this document, but one way of going about
- this might be to generate some small (say a few hundred patches)
- with targen &amp; pritntarg with different total ink limits, and
- printing them out, making the ink limit as large as possible without
- striking problems that are caused by too much ink.<br>
- <br>
- Generally one wants to use the maximum possible amount of ink to
- maximize the gamut available on the device. For most CMYK devices,
- an ink limit between 200 and 400 is usual, but and ink limit of 250%
- or over is generally desirable for reasonably dense blacks and dark
- saturated colors. And ink limit of less than 200% will begin to
- compromise the fully saturated gamut, as secondary colors (ie
- combinations of any two primary colorants) will not be able to reach
- full strength.<br>
- <br>
- Once an ink limit is used in printing the characterization test
- chart for a device, it becomes a critical parameter in knowing what
- the characterized gamut of the device is. If after printing the test
- chart, a greater ink limit were to be used, the the software would
- effectively be extrapolating the device behaviour at total ink
- levels beyond that used in the test chart, leading to inaccuracies.<br>
- <br>
- Generally in Argyll, the ink limit is established when creating the
- test chart values, and then carried through the profile making
- process automatically. Once the profile has been made however, the
- ink limit is no longer recorded, and you, the user, will have to
- keep track of it if the ICC profile is used in any program than
- needs to know the usable gamut of the device.<br>
- <br>
- <br>
- Lets consider two devices in our examples, "PrinterA" which is an
- "RGB" device, and "PrinterB" which is CMYK, and has a target ink
- limit of 250%. <br>
- <br>
- The simplest approach is to make a set of test values that is
- independent of the characteristics of the particular device:<br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
- <a href="targen.html#p1">PrinterA</a><br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
- <a href="targen.html#f">-f1053</a> <a href="targen.html#p1">PrinterB</a><br>
- <br>
- The number of patches chosen here happens to be right for an A4
- paper size being read using a Spectroscan instrument. See the <a
- href="targen.html#Table">table</a> in&nbsp; the <a
- href="targen.html">targen</a> documentation for some other
- suggested numbers.<br>
- <br>
- If there is a preliminary or previous profile called "OldPrinterA"
- available, and we want to try creating a "pre-conditioned" set of
- test values that will more efficiently sample the device response,
- then the following would achieve this:<u><br>
- </u><br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
- <a href="targen.html#c">-c OldPrinterA</a>&nbsp;<a
- href="targen.html#p1">PrinterA</a><br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
- <a href="targen.html#f">-f1053</a> <a href="targen.html#c">-c
- OldPrinterB</a> <a href="targen.html#p1">PrinterB</a><br>
- <a href="targen.html#p1"></a><br>
- <br>
- The output of <b>targen</b> will be the file PrinterA.ti1 and
- PrinterB.ti1 respectively, containing the device space test values,
- as well as expected CIE values used for chart recognition purposes.<br>
- <br>
- <h4><a name="PP2b"></a>Printing a print profile test chart<br>
- <br>
- </h4>
- The next step is turn the test values in to a PostScript or TIFF
- raster test file that can printed on the device. The basic
- information that needs to be supplied is the type of instrument that
- will be used to read the patches, as well as the paper size it is to
- be formatted for.<br>
- <br>
- For an X-Rite DTP41, the following would be typical:<br>
- <br>
- <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
- <a href="printtarg.html#i">-i41</a> <a href="printtarg.html#p">-pA4</a>
- <a href="printtarg.html#p1">PrinterA</a><br>
- &nbsp;<br>
- For a Gretag Eye-One Pro, the following would be typical:<br>
- <br>
- <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
- <a href="printtarg.html#i">-ii1</a> <a href="printtarg.html#p">-pA4</a>
- <a href="printtarg.html#p1">PrinterA</a><br>
- <br>
- For using with a scanner as a colorimeter, the Gretag Spectroscan
- layout is suitable, but the <a href="printtarg.html#s">-s</a> flag
- should be used so as to generate a layout suitable for scan
- recognition, as well as generating the scan recognition template
- files. (You probably want to use less patches with <span
- style="font-weight: bold;">targen</span>, when using the <span
- style="font-weight: bold;">printtarg -s</span> flag, e.g. 1026
- patches for an A4R page, etc.) The following would be typical:<br>
- <br>
- <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
- <a href="printtarg.html#s">-s</a> <a href="printtarg.html#i">-iSS</a>
- <a href="printtarg.html#p">-pA4R</a> <a href="printtarg.html#p1">PrinterA</a><br>
- <span style="font-weight: bold;"><br>
- printtarg</span> reads the PrinterA.ti1 file, creates a
- PrinterA.ti2 file containing the layout information as well as the
- device values and expected CIE values, as well as a PrinterA.ps file
- containing the test chart. If the <span style="font-weight: bold;">-s</span>
- flag is used, one or more PrinterA.cht files is created to allow the
- <a href="scanin.html">scanin</a> program to recognize the chart.<br>
- <br>
- To create TIFF raster files rather than PostScript, use the <a
- href="printtarg.html#t"><span style="font-weight: bold;">-t</span></a>
- flag.<br>
- <br>
- <span style="font-weight: bold;">GSview</span> is a good program to
- use to check what the PostScript file will look like, without
- actually printing it out. You could also use <span
- style="font-weight: bold;">Photoshop</span> or <span
- style="font-weight: bold;">ImageMagick</span> for this purpose.<br>
- <br>
- The last step is to print the chart out.<br>
- <br>
- Using a suitable PostScript or raster file printing program,
- downloader, print the chart. If you are not using a TIFF test chart,
- and you do not have a PostScript capable printer, then an
- interpreter like GhostScript or even Photoshop could be used to
- rasterize the file into something that can be printed. Note that it
- is important that the PostScript interpreter or TIFF printing
- application and printer configuration is setup for a device
- profiling run, and that any sort of color conversion of color
- correction be turned off so that the device values in the PostScript
- or TIFF file are sent directly to the device. If the device has a
- calibration system, then it would be usual to have setup and
- calibrated the device before starting the profiling run, and to
- apply calibration to the chart values. If Photoshop was to be used,
- then either the chart needs to be a single page, or separate .eps or
- .tiff files for each page should be used, so that they can be
- converted and printed one at a time (see the <a
- href="printtarg.html#e">-e</a> and <a href="printtarg.html#t">-t</a>
- flags).<br>
- <br>
- <h4><a name="PP3"></a>Reading a print test chart using an instrument</h4>
- Once the test chart has been printed, the color of the patches needs
- to be read using a suitable instrument.<br>
- <br>
- Several different instruments are currently supported, some that
- need to be used patch by patch, some read a strip at a time, and
- some read a sheet at a time. See <a href="instruments.html">instruments</a>
- for a current list.<br>
- <br>
- The instrument needs to be connected to your computer before running
- the <a href="chartread.html">chartread</a> command. Both serial
- port and USB connected Instruments are supported. A serial port to
- USB adapter might have to be used if your computer doesn't have any
- serial ports, and you have a serial interface connected instrument.<br>
- <br>
- If you run <a href="chartread.html">chartread</a> so as to print
- out its usage message (ie. by using a <span style="font-weight:
- bold;">-?</span> or <span style="font-weight: bold;">--</span>
- flags), then it will list any identified serial ports or USB
- connected instruments, and their corresponding number for the <a
- href="chartread.html#c">-c</a> option. By default, <a
- href="chartread.html">chartread</a> will try to connect to the
- first available USB instrument, or an instrument on the first serial
- port.<br>
- <br>
- The only arguments required is to specify the basename of the .ti2
- file. If a non-default serial port is to be used, then the <span
- style="font-weight: bold;">-c</span> option would also be
- specified.<br>
- <br>
- &nbsp;e.g. for a Spectroscan on the second port:<br>
- <br>
- <a href="chartread.html">chartread</a> <a href="chartread.html#c">-c2</a>
- <a href="chartread.html#p1">PrinterA</a><br>
- <br>
- For a DTP41 to the default serial port:<br>
- <br>
- <a href="chartread.html">chartread</a><a href="chartread.html#i"></a>
- <a href="chartread.html#p1">PrinterA</a><br>
- <br>
- <span style="font-weight: bold;">chartread</span> will interactively
- prompt you through the process of reading each sheet or strip. See <a
- href="chartread.html">chartread</a> for more details on the
- responses for each type of instrument. Continue with <a
- href="Scenarios.html#PP5">Creating a printer profile</a>.<br>
- <br>
- <h4><a name="PP4"></a>Reading a print test chart using a scanner or
- camera<br>
- </h4>
- <br>
- Argyll supports using a scanner or even a camera as a substitute for
- a colorimeter. While a scanner or camera is no replacement for a
- color measurement instrument, it may give acceptable results in some
- situations, and may give better results than a generic profile for a
- printing device.<br>
- <br>
- The main limitation of the scanner-as-colorimeter approach are:<br>
- <br>
- * The scanner dynamic range and/or precision may not match the
- printers or what is required for a good profile.<br>
- * The spectral interaction of the scanner test chart and printer
- test chart with the scanner spectral response can cause color
- errors.<br>
- * Spectral differences caused by different black amounts in the
- print test chart can cause color errors. <br>
- * The scanner reference chart gamut may be much smaller than the
- printers gamut, making the scanner profile too inaccurate to be
- useful. <br>
- <br>
- As well as some of the above, a camera may not be suitable if it
- automatically adjusts exposure or white point when taking a picture,
- and this behavior cannot be disabled.<br>
- <br>
- The end result is often a profile that has a noticeable color cast,
- compared to a profile created using a colorimeter or spectrometer.<br>
- <br>
- <br>
- It is assumed that you have created a scanner or camera profile
- following the <a
- href="http://www.argyllcms.com/doc/Scenarios.html#PS1">procedure</a>
- outline above. For best possible results it is advisable to both
- profile the scanner or camera, and use it in scanning the printed
- test chart, in as "raw" mode as possible (i.e. using 16 bits per
- component images, if the scanner or camera is capable of doing so;
- not setting white or black points, using a fixed exposure etc.). It
- is generally advisable to create a LUT type input profile, and use
- the <a href="http://www.argyllcms.com/doc/colprof.html#u">-u</a>
- flag to avoid clipping scanned value whiter than the input
- calibration chart.<br>
- <br>
- Scan or photograph your printer chart (or charts) on the scanner or
+
+
+
+ documentation</a>).<br>
+ <br>
+ To create the scanner .ti3 file, run the <b>scanin</b> tool as
+ follows (assuming an IT8 chart is being used):<br>
+ <br>
+ <a href="scanin.html"> scanin</a> -v scanner.tif It8.cht It8ref.txt<br>
+ <br>
+ "It8ref.txt" or "It8ref.cie" is assumed to be the name of the CIE
+ reference file supplied by the chart manufacturer. The resulting
+ file will be named "<b>scanner.ti3</b>".<br>
+ <br>
+ <span style="font-weight: bold;">scanin</span> will process 16 bit
+ per component .tiff files, which (if the scanner is capable of
+ creating such files),&nbsp; may improve the quality of the profile.
+ <br>
+ <br>
+ If you have any doubts about the correctness of the chart
+ recognition, or the subsequent profile's delta E report is unusual,
+ then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
+ and examine the <span style="font-weight: bold;">diag.tif</span>
+ diagnostic file, to make sure that the patches are identified and
+ aligned correctly. If you have problems getting good automatic
+ alignment, then consider doing a manual alignment by locating the
+ fiducial marks on your scan, and feeding them into scanin <a
+ href="scanin.html#F">-F</a> parameters. The fiducial marks should
+ be listed in a clockwise direction starting at the top left.<br>
+ <h4><a name="PS4"></a>Creating a scanner or camera input profile</h4>
+ Similar to a display profile, an input profile can be either a
+ shaper/matrix or LUT based profile. Well behaved input devices will
+ probably give the best results with a shaper/matrix profile, and
+ this may also be the best choice if your test chart has a small or
+ unevenly distributed set of test patchs (ie. the IT8.7.2). If a
+ shaper/matrix profile is a poor fit, consider using a LUT type
+ profile.<br>
+ <br>
+ When creating a LUT type profile, there is the choice of XYZ or
+ L*a*b* PCS (Device independent, Profile Connection Space). Often for
+ input devices, it is better to choose the XYZ PCS, as this may be a
+ better fit given that input devices are usually close to being
+ linearly additive in behaviour.<br>
+ <br>
+ If the purpose of the input profile is to use it as a substitute for
+ a colorimeter, then the <b>-u</b> flag should be used to avoid
+ clipping values above the white point. Unless the shaper/matrix type
+ profile is a very good fit, it is probably advisable to use a LUT
+ type profile in this situation.<br>
+ <br>
+ To create a matrix/shaper profile, the following suffices:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner</a> <a href="colprof.html#E">A"</a>
+ <a href="colprof.html#q">-qm</a> <a href="colprof.html#a">-as</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ For an XYZ PCS LUT based profile then the following would be used:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-ax</a> <a href="colprof.html#p1">scanner</a><br>
+ <br>
+ For the purposes of a poor mans colorimeter, the following would
+ generally be used:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-ax</a> <a href="colprof.html#u">-u</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the sample data and profile is behaving
+ reasonably. Depending on the type of device, and the consistency of
+ the readings, average errors of 5 or less, and maximum errors of 15
+ or less would normally be expected. If errors are grossly higher
+ than this, then this is an indication that something is seriously
+ wrong with the device measurement, or profile creation.<br>
+ <br>
+ If profiling a <span style="font-weight: bold;">camera</span> in <span
+ style="font-weight: bold;">RAW</span> mode, then there may be some
+ advantage in creating a pure matrix only profile, in which it is
+ assumed that the camera response is completely linear. This may
+ reduce extrapolation artefacts. If setting the white point will be
+ done in some application, then it may also be an advantage to use
+ the <span style="font-weight: bold;">-u</span> flag and avoid
+ setting the white point to that of the profile chart:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Camera"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-am</a> <a href="colprof.html#u">-u</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ <br>
+ <hr size="2" width="100%">
+ <h3><a name="PP1"></a>Profiling Printers<br>
+ </h3>
+ The overall process is to create a set of device measurement target
+ values, print them out, measure them, and then create an ICC profile
+ from the measurements. If the printer is an RGB based printer, then
+ the process is only slightly more complicated than profiling a
+ display. If the printer is CMYK based, then some additional
+ parameters are required to set the total ink limit (TAC) and
+ &nbsp;black generation curve.<br>
+ <h4><a name="PP2"></a>Creating a print profile test chart</h4>
+ The first step in profiling any output device, is to create a set of
+ device colorspace test values. The important parameters needed are:<br>
+ <ul>
+ <li>What colorspace does the device use ?</li>
+ <li>How many test patches do I want to use/what paper size do I
+ want to use ?</li>
+ <li>What instrument am I going to use to read the patches ?<br>
+ </li>
+ <li>If it is a CMYK device, what is the total ink limit ?<br>
+ </li>
+ <li>What information do I already have about how the device
+ behaves ?</li>
+ </ul>
+ Most printers running through simple drivers will appear as if they
+ are RGB devices. In fact there is no such thing as a real RGB
+ printer, since printers use white media and the colorant must
+ subtract from the light reflected on it to create color, but the
+ printer itself turns the incoming RGB into the native print
+ colorspace, so for this reason we will tell targen to use the "Print
+ RGB" colorspace, so that it knows that it's really a subtractive
+ media. Other drivers will drive a printer more directly, and will
+ expect a CMYK profile. [Currently Argyll is not capable of creating
+ an ICC profile for devices with more colorants than CMYK. When this
+ capability is introduced, it will by creating an additional
+ separation profile which then allows the printer to be treated as a
+ CMY or CMYK printer.] One way of telling what sort of profile is
+ expected for your device is to examine an existing profile for that
+ device using <a href="http://www.argyllcms.com/doc/iccdump.html">iccdump</a>.<br>
+ <br>
+ The number of test patches will depend somewhat on what quality
+ profile you want to make, how well behaved the printer is, as well
+ as the effort needed to read the number of test values. Generally it
+ is convenient to fill a certain paper size with the maximum number
+ of test values that will fit.<br>
+ <br>
+ At a minimum, for an "RGB" device, a few hundred values are needed
+ (400-1000). For high quality CMYK profiles, 1000-3000 is not an
+ unreasonable number of patches.<br>
+ <br>
+ To assist the determination of test patch values, it can help to
+ have a rough idea of how the device behaves, so that the device test
+ point locations can be pre-conditioned. This could be in the form of
+ an ICC profile of a similar device, or a lower quality, or previous
+ profile for that particular device. If one were going to make a very
+ high quality Lut based profile, then it might be worthwhile to make
+ up a smaller, preliminary shaper/matrix profile using a few hundred
+ test points, before embarking on testing the device with several
+ thousand.<br>
+ <br>
+ The documentation for the <a
+ href="http://www.argyllcms.com/doc/targen.html">targen</a> tool
+ lists a <a href="http://www.argyllcms.com/doc/targen.html#Table">table</a>
+ of paper sizes and number of &nbsp;patches for typical situations.<br>
+ <br>
+ For a CMYK device, a total ink limit usually needs to be specified.
+ Sometimes a device will have a maximum total ink limit set by its
+ manufacturer or operator, and some CMYK systems (such as chemical
+ proofing systems) don't have any limit. Typical printing devices
+ such as Xerographic printers, inkjet printers and printing presses
+ will have a limit. The exact procedure for determining an ink limit
+ is outside the scope of this document, but one way of going about
+ this might be to generate some small (say a few hundred patches)
+ with targen &amp; pritntarg with different total ink limits, and
+ printing them out, making the ink limit as large as possible without
+ striking problems that are caused by too much ink.<br>
+ <br>
+ Generally one wants to use the maximum possible amount of ink to
+ maximize the gamut available on the device. For most CMYK devices,
+ an ink limit between 200 and 400 is usual, but and ink limit of 250%
+ or over is generally desirable for reasonably dense blacks and dark
+ saturated colors. And ink limit of less than 200% will begin to
+ compromise the fully saturated gamut, as secondary colors (ie
+ combinations of any two primary colorants) will not be able to reach
+ full strength.<br>
+ <br>
+ Once an ink limit is used in printing the characterization test
+ chart for a device, it becomes a critical parameter in knowing what
+ the characterized gamut of the device is. If after printing the test
+ chart, a greater ink limit were to be used, the the software would
+ effectively be extrapolating the device behaviour at total ink
+ levels beyond that used in the test chart, leading to inaccuracies.<br>
+ <br>
+ Generally in Argyll, the ink limit is established when creating the
+ test chart values, and then carried through the profile making
+ process automatically. Once the profile has been made however, the
+ ink limit is no longer recorded, and you, the user, will have to
+ keep track of it if the ICC profile is used in any program than
+ needs to know the usable gamut of the device.<br>
+ <br>
+ <br>
+ Lets consider two devices in our examples, "PrinterA" which is an
+ "RGB" device, and "PrinterB" which is CMYK, and has a target ink
+ limit of 250%. <br>
+ <br>
+ The simplest approach is to make a set of test values that is
+ independent of the characteristics of the particular device:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
+ <a href="targen.html#p1">PrinterA</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
+ <a href="targen.html#f">-f1053</a> <a href="targen.html#p1">PrinterB</a><br>
+ <br>
+ The number of patches chosen here happens to be right for an A4
+ paper size being read using a Spectroscan instrument. See the <a
+ href="targen.html#Table">table</a> in&nbsp; the <a
+ href="targen.html">targen</a> documentation for some other
+ suggested numbers.<br>
+ <br>
+ If there is a preliminary or previous profile called "OldPrinterA"
+ available, and we want to try creating a "pre-conditioned" set of
+ test values that will more efficiently sample the device response,
+ then the following would achieve this:<u><br>
+ </u><br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
+ <a href="targen.html#c">-c OldPrinterA</a>&nbsp;<a
+ href="targen.html#p1">PrinterA</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
+ <a href="targen.html#f">-f1053</a> <a href="targen.html#c">-c
+ OldPrinterB</a> <a href="targen.html#p1">PrinterB</a><br>
+ <a href="targen.html#p1"></a><br>
+ <br>
+ The output of <b>targen</b> will be the file PrinterA.ti1 and
+ PrinterB.ti1 respectively, containing the device space test values,
+ as well as expected CIE values used for chart recognition purposes.<br>
+ <br>
+ <h4><a name="PP2b"></a>Printing a print profile test chart<br>
+ <br>
+ </h4>
+ The next step is turn the test values in to a PostScript or TIFF
+ raster test file that can printed on the device. The basic
+ information that needs to be supplied is the type of instrument that
+ will be used to read the patches, as well as the paper size it is to
+ be formatted for.<br>
+ <br>
+ For an X-Rite DTP41, the following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#i">-i41</a> <a href="printtarg.html#p">-pA4</a>
+ <a href="printtarg.html#p1">PrinterA</a><br>
+ &nbsp;<br>
+ For a Gretag Eye-One Pro, the following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#i">-ii1</a> <a href="printtarg.html#p">-pA4</a>
+ <a href="printtarg.html#p1">PrinterA</a><br>
+ <br>
+ For using with a scanner as a colorimeter, the Gretag Spectroscan
+ layout is suitable, but the <a href="printtarg.html#s">-s</a> flag
+ should be used so as to generate a layout suitable for scan
+ recognition, as well as generating the scan recognition template
+ files. (You probably want to use less patches with <span
+ style="font-weight: bold;">targen</span>, when using the <span
+ style="font-weight: bold;">printtarg -s</span> flag, e.g. 1026
+ patches for an A4R page, etc.) The following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#s">-s</a> <a href="printtarg.html#i">-iSS</a>
+ <a href="printtarg.html#p">-pA4R</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <span style="font-weight: bold;"><br>
+ printtarg</span> reads the PrinterA.ti1 file, creates a
+ PrinterA.ti2 file containing the layout information as well as the
+ device values and expected CIE values, as well as a PrinterA.ps file
+ containing the test chart. If the <span style="font-weight: bold;">-s</span>
+ flag is used, one or more PrinterA.cht files is created to allow the
+ <a href="scanin.html">scanin</a> program to recognize the chart.<br>
+ <br>
+ To create TIFF raster files rather than PostScript, use the <a
+ href="printtarg.html#t"><span style="font-weight: bold;">-t</span></a>
+ flag.<br>
+ <br>
+ <span style="font-weight: bold;">GSview</span> is a good program to
+ use to check what the PostScript file will look like, without
+ actually printing it out. You could also use <span
+ style="font-weight: bold;">Photoshop</span> or <span
+ style="font-weight: bold;">ImageMagick</span> for this purpose.<br>
+ <br>
+ The last step is to print the chart out.<br>
+ <br>
+ Using a suitable PostScript or raster file printing program,
+ downloader, print the chart. If you are not using a TIFF test chart,
+ and you do not have a PostScript capable printer, then an
+ interpreter like GhostScript or even Photoshop could be used to
+ rasterize the file into something that can be printed. Note that it
+ is important that the PostScript interpreter or TIFF printing
+ application and printer configuration is setup for a device
+ profiling run, and that any sort of color conversion of color
+ correction be turned off so that the device values in the PostScript
+ or TIFF file are sent directly to the device. If the device has a
+ calibration system, then it would be usual to have setup and
+ calibrated the device before starting the profiling run, and to
+ apply calibration to the chart values. If Photoshop was to be used,
+ then either the chart needs to be a single page, or separate .eps or
+ .tiff files for each page should be used, so that they can be
+ converted and printed one at a time (see the <a
+ href="printtarg.html#e">-e</a> and <a href="printtarg.html#t">-t</a>
+ flags).<br>
+ <br>
+ <h4><a name="PP3"></a>Reading a print test chart using an instrument</h4>
+ Once the test chart has been printed, the color of the patches needs
+ to be read using a suitable instrument.<br>
+ <br>
+ Several different instruments are currently supported, some that
+ need to be used patch by patch, some read a strip at a time, and
+ some read a sheet at a time. See <a href="instruments.html">instruments</a>
+ for a current list.<br>
+ <br>
+ The instrument needs to be connected to your computer before running
+ the <a href="chartread.html">chartread</a> command. Both serial
+ port and USB connected Instruments are supported. A serial port to
+ USB adapter might have to be used if your computer doesn't have any
+ serial ports, and you have a serial interface connected instrument.<br>
+ <br>
+ If you run <a href="chartread.html">chartread</a> so as to print
+ out its usage message (ie. by using a <span style="font-weight:
+ bold;">-?</span> or <span style="font-weight: bold;">--</span>
+ flags), then it will list any identified serial ports or USB
+ connected instruments, and their corresponding number for the <a
+ href="chartread.html#c">-c</a> option. By default, <a
+ href="chartread.html">chartread</a> will try to connect to the
+ first available USB instrument, or an instrument on the first serial
+ port.<br>
+ <br>
+ The only arguments required is to specify the basename of the .ti2
+ file. If a non-default serial port is to be used, then the <span
+ style="font-weight: bold;">-c</span> option would also be
+ specified.<br>
+ <br>
+ &nbsp;e.g. for a Spectroscan on the second port:<br>
+ <br>
+ <a href="chartread.html">chartread</a> <a href="chartread.html#c">-c2</a>
+ <a href="chartread.html#p1">PrinterA</a><br>
+ <br>
+ For a DTP41 to the default serial port:<br>
+ <br>
+ <a href="chartread.html">chartread</a><a href="chartread.html#i"></a>
+ <a href="chartread.html#p1">PrinterA</a><br>
+ <br>
+ <span style="font-weight: bold;">chartread</span> will interactively
+ prompt you through the process of reading each sheet or strip. See <a
+ href="chartread.html">chartread</a> for more details on the
+ responses for each type of instrument. Continue with <a
+ href="Scenarios.html#PP5">Creating a printer profile</a>.<br>
+ <br>
+ <h4><a name="PP4"></a>Reading a print test chart using a scanner or
+ camera<br>
+ </h4>
+ <br>
+ Argyll supports using a scanner or even a camera as a substitute for
+ a colorimeter. While a scanner or camera is no replacement for a
+ color measurement instrument, it may give acceptable results in some
+ situations, and may give better results than a generic profile for a
+ printing device.<br>
+ <br>
+ The main limitation of the scanner-as-colorimeter approach are:<br>
+ <br>
+ * The scanner dynamic range and/or precision may not match the
+ printers or what is required for a good profile.<br>
+ * The spectral interaction of the scanner test chart and printer
+ test chart with the scanner spectral response can cause color
+ errors.<br>
+ * Spectral differences caused by different black amounts in the
+ print test chart can cause color errors. <br>
+ * The scanner reference chart gamut may be much smaller than the
+ printers gamut, making the scanner profile too inaccurate to be
+ useful. <br>
+ <br>
+ As well as some of the above, a camera may not be suitable if it
+ automatically adjusts exposure or white point when taking a picture,
+ and this behavior cannot be disabled.<br>
+ <br>
+ The end result is often a profile that has a noticeable color cast,
+ compared to a profile created using a colorimeter or spectrometer.<br>
+ <br>
+ <br>
+ It is assumed that you have created a scanner or camera profile
+ following the <a
+ href="http://www.argyllcms.com/doc/Scenarios.html#PS1">procedure</a>
+ outline above. For best possible results it is advisable to both
+ profile the scanner or camera, and use it in scanning the printed
+ test chart, in as "raw" mode as possible (i.e. using 16 bits per
+ component images, if the scanner or camera is capable of doing so;
+ not setting white or black points, using a fixed exposure etc.). It
+ is generally advisable to create a LUT type input profile, and use
+ the <a href="http://www.argyllcms.com/doc/colprof.html#u">-u</a>
+ flag to avoid clipping scanned value whiter than the input
+ calibration chart.<br>
+ <br>
+ Scan or photograph your printer chart (or charts) on the scanner or
camera previously profiled. <big><span style="font-weight: bold;">The
@@ -1909,97 +1967,100 @@ href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.t
- scanner or camera must be configured and used exactly the same
- as it was when it was profiled.</span></big><br>
- <br>
- I will assume the resulting scan/photo input file is called <span
- style="font-weight: bold;">PrinterB.tif</span> (or <span
- style="font-weight: bold;">PrinterB1.tif</span>, <span
- style="font-weight: bold;">PrinterB2.tif</span> etc. in the case
- of multiple charts). As with profiling the scanner or camera, the
- raster file need only be roughly cropped so as to contain the test
- chart.<br>
- <br>
- The scanner recognition files created when <span
- style="font-weight: bold;">printtarg</span> was run is assumed to
- be called <span style="font-weight: bold;">PrinterB.cht</span>.
- Using the scanner profile created previously (assumed to be called <span
- style="font-weight: bold;">scanner.icm</span>), the printer test
- chart scan patches are converted to CIE values using the <span
- style="font-weight: bold;">scanin</span> tool:<br>
- <br>
- <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
- href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB.tif</a>
- <a href="scanin.html#cp2">PrinterB.cht</a> <a
- href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
- <br>
- If there were multiple test chart pages, the results would be
- accumulated page by page using the <a href="scanin.html#ca">-ca</a>
- option, ie., if there were 3 pages:<br>
- <br>
- <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
- href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB1.tif</a>
- <a href="scanin.html#cp2">PrinterB1.cht</a> <a
- href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
- <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
- href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB2.tif</a>
- <a href="scanin.html#cp2">PrinterB2.cht</a> <a
- href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
- <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
- href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB3.tif</a>
- <a href="scanin.html#cp2">PrinterB3.cht</a> <a
- href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
- <br>
- Now that the <span style="font-weight: bold;">PrinterB.ti3</span>
- data has been obtained, the profile continue in the next section
- with <span style="font-weight: bold;">Creating a printer profile</span>.<br>
- <br>
- If you have any doubts about the correctness of the chart
- recognition, or the subsequent profile's delta E report is unusual,
- then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
- and examine the <span style="font-weight: bold;">diag.tif</span>
- diagnostic file.<br>
- <h4><a name="PP5"></a>Creating a printer profile<br>
- </h4>
- Creating an RGB based printing profile is very similar to creating a
- display device profile. For a CMYK printer, some additional
- information is needed to set the black generation.<br>
- <br>
- Where the resulting profile will be used conventionally (ie. using <a
- href="collink.html">collink</a> <a href="collink.html#s">-s</a>,
- or <a href="cctiff.html">cctiff</a> or most other "dumb" CMMs) it
- is important to specify that gamut mapping should be computed for
- the output (B2A) perceptual and saturation tables. This is done by
- specifying a device profile as the parameter to the <a
- href="colprof.html">colprof</a> <a href="colprof.html#S">-S</a>
- flag. When you intend to create a "general use" profile, it can be a
- good technique to specify the source gamut as the opposite type of
- profile to that being created, i.e. if a printer profile is being
- created, specify a display profile (e.g. sRGB) as the source gamut.
- If a display profile is being created, then specify a printer
- profile as the source (e.g. Figra, SWOP etc.).&nbsp; When linking to
- the profile you have created this way as the output profile, then
- use perceptual intent if the source is the opposite type, and
- relative colorimetric if it is the same type.<br>
- <br>
- "Opposite type of profile" refers to the native gamut of the device,
- and what its fundamental nature is, additive or subtractive. An
- emissive display will have additive primaries (R, G &amp; B), while
- a reflective print, will have subtractive primaries (C, M, Y &amp;
- possibly others), irrespective of what colorspace the printer is
- driven in (a printer might present an RGB interface, but internally
- this will be converted to CMY, and it will have a CMY type of
- gamut).&nbsp; Because of the complimentary nature of additive and
- subtractive device primary colorants, these types of devices have
- the most different gamuts, and hence need the most gamut mapping to
- convert from one colorspace to the other.<br>
- <br>
- If you are creating a profile for a specific purpose, intending to
- link it to a specific input profile, then you will get the best
- results by specifying that source profile as the source gamut.<br>
- <br>
- If a profile is only going to be used as an input profile, or is
- going to be used with a "smart" CMM (e.g. <a href="collink.html">collink</a>
+
+
+
+ scanner or camera must be configured and used exactly the same
+ as it was when it was profiled.</span></big><br>
+ <br>
+ I will assume the resulting scan/photo input file is called <span
+ style="font-weight: bold;">PrinterB.tif</span> (or <span
+ style="font-weight: bold;">PrinterB1.tif</span>, <span
+ style="font-weight: bold;">PrinterB2.tif</span> etc. in the case
+ of multiple charts). As with profiling the scanner or camera, the
+ raster file need only be roughly cropped so as to contain the test
+ chart.<br>
+ <br>
+ The scanner recognition files created when <span
+ style="font-weight: bold;">printtarg</span> was run is assumed to
+ be called <span style="font-weight: bold;">PrinterB.cht</span>.
+ Using the scanner profile created previously (assumed to be called <span
+ style="font-weight: bold;">scanner.icm</span>), the printer test
+ chart scan patches are converted to CIE values using the <span
+ style="font-weight: bold;">scanin</span> tool:<br>
+ <br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB.tif</a>
+ <a href="scanin.html#cp2">PrinterB.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <br>
+ If there were multiple test chart pages, the results would be
+ accumulated page by page using the <a href="scanin.html#ca">-ca</a>
+ option, ie., if there were 3 pages:<br>
+ <br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB1.tif</a>
+ <a href="scanin.html#cp2">PrinterB1.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB2.tif</a>
+ <a href="scanin.html#cp2">PrinterB2.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB3.tif</a>
+ <a href="scanin.html#cp2">PrinterB3.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <br>
+ Now that the <span style="font-weight: bold;">PrinterB.ti3</span>
+ data has been obtained, the profile continue in the next section
+ with <span style="font-weight: bold;">Creating a printer profile</span>.<br>
+ <br>
+ If you have any doubts about the correctness of the chart
+ recognition, or the subsequent profile's delta E report is unusual,
+ then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
+ and examine the <span style="font-weight: bold;">diag.tif</span>
+ diagnostic file.<br>
+ <h4><a name="PP5"></a>Creating a printer profile<br>
+ </h4>
+ Creating an RGB based printing profile is very similar to creating a
+ display device profile. For a CMYK printer, some additional
+ information is needed to set the black generation.<br>
+ <br>
+ Where the resulting profile will be used conventionally (ie. using <a
+ href="collink.html">collink</a> <a href="collink.html#s">-s</a>,
+ or <a href="cctiff.html">cctiff</a> or most other "dumb" CMMs) it
+ is important to specify that gamut mapping should be computed for
+ the output (B2A) perceptual and saturation tables. This is done by
+ specifying a device profile as the parameter to the <a
+ href="colprof.html">colprof</a> <a href="colprof.html#S">-S</a>
+ flag. When you intend to create a "general use" profile, it can be a
+ good technique to specify the source gamut as the opposite type of
+ profile to that being created, i.e. if a printer profile is being
+ created, specify a display profile (e.g. sRGB) as the source gamut.
+ If a display profile is being created, then specify a printer
+ profile as the source (e.g. Figra, SWOP etc.).&nbsp; When linking to
+ the profile you have created this way as the output profile, then
+ use perceptual intent if the source is the opposite type, and
+ relative colorimetric if it is the same type.<br>
+ <br>
+ "Opposite type of profile" refers to the native gamut of the device,
+ and what its fundamental nature is, additive or subtractive. An
+ emissive display will have additive primaries (R, G &amp; B), while
+ a reflective print, will have subtractive primaries (C, M, Y &amp;
+ possibly others), irrespective of what colorspace the printer is
+ driven in (a printer might present an RGB interface, but internally
+ this will be converted to CMY, and it will have a CMY type of
+ gamut).&nbsp; Because of the complimentary nature of additive and
+ subtractive device primary colorants, these types of devices have
+ the most different gamuts, and hence need the most gamut mapping to
+ convert from one colorspace to the other.<br>
+ <br>
+ If you are creating a profile for a specific purpose, intending to
+ link it to a specific input profile, then you will get the best
+ results by specifying that source profile as the source gamut.<br>
+ <br>
+ If a profile is only going to be used as an input profile, or is
+ going to be used with a "smart" CMM (e.g. <a href="collink.html">collink</a>
<a href="collink.html#g">-g</a> or <a href="collink.html#G">-G</a>),
then
@@ -2061,82 +2122,94 @@ then
- it can save considerable processing time and space if the -b flag is
- used, and the -S flag not used.<br>
- <br>
- For an RGB printer intended to print RGB originals, the following
- might be a typical profile usage:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
- <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
- <a href="colprof.html#p1">PrinterA</a><br>
- <br>
- or if you intent to print from Fogra, SWOP or other standard CMYK
- style originals:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#S">-S</a><a href="colprof.html#S">
- fogra39l.icm</a> <a href="colprof.html#c">-cmt</a> <a
- href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterA</a><br>
- <br>
- If you know what colorspace your originals are in, use that as the
- argument to <span style="font-weight: bold;">-S</span>.<br>
- <br>
- If your viewing environment for the display and print doesn't match
- the ones implied by the <a href="colprof.html#c">-cmt</a> and <a
- href="colprof.html#d">-dpp</a> options, leave them out, and
- evaluate what, if any appearance transformation is appropriate for
- your environment at a later stage.<br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the sample data and profile is behaving
- reasonably. Depending on the type of device, and the consistency of
- the readings, average errors of 5 or less, and maximum errors of 15
- or less would normally be expected. If errors are grossly higher
- than this, then this is an indication that something is seriously
- wrong with the device measurement, or profile creation.
- <h4><a name="PP6"></a>Choosing a black generation curve (and other
- CMYK printer options)<br>
- </h4>
- For a CMYK printer, it would be normal to specify the type of black
- generation, either as something simple, or as a specific curve. The
- documentation&nbsp; in <a href="colprof.html#k">colprof</a> for the
- details of the options.<span style="font-weight: bold;"><br>
- <br>
- Note</span> that making a good choice of black generation curve
- can affect things such as: how robust neutrals are given printer
- drift or changes in viewing lighting, how visible screening is, and
- how smooth looking the B2A conversion is.<br>
- <br>
- For instance, maximizing the level of K will mean that the neutral
- colors are composed of greater amounts of Black ink, and black ink
- retains its neutral appearance irrespective of printer behavior or
- the spectrum of the illuminant used to view the print. On the other
- hand, output which is dominantly from one of the color channels will
- tend to emphasize the screening pattern and any unevenness (banding
- etc.) of that channel, and the black channel in particular has the
- highest visibility. So in practice, some balance between the levels
- of the four channels is probably best, with more K if the screening
- is fine and a robust neutral balance is important, or less K if the
- screening is more visible and neutral balance is less critical. The
- levels of K at the edges of the gamut of the device will be fixed by
- the nature of the ink combinations that maximize the gamut (ie.
- typically zero ink for light chromatic colors, some combination for
- dark colors, and a high level of black for very dark near neutrals),
- and it is also usually important to set a curve that smoothly
- transitions to the K values at the gamut edges. Dramatic changes in
- K imply equally dramatic changes in CMY, and these abrupt
- transitions will reveal the limited precision and detail that can be
- captured in a lookup table based profile, often resulting in a
- "bumpy" looking output.<br>
- <br>
- If you want to experiment with the various black generation
- parameters, then it might be a good idea to create a preliminary
- profile (using <a href="colprof.html#q">-ql</a> <a
- href="colprof.html#b">-b</a> <a href="colprof.html#ni">-no</a>, <a
+
+
+
+ it can save considerable processing time and space if the -b flag is
+ used, and the -S flag not used.<br>
+ <br>
+ For an RGB printer intended to print RGB originals, the following
+ might be a typical profile usage:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
+ <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#p1">PrinterA</a><br>
+ <br>
+ or if you intent to print from Fogra, SWOP or other standard CMYK
+ style originals:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S">
+ fogra39l.icm</a> <a href="colprof.html#c">-cmt</a> <a
+ href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterA</a><br>
+ <br>
+ If you know what colorspace your originals are in, use that as the
+ argument to <span style="font-weight: bold;">-S</span>.<br>
+ <br>
+ If your viewing environment for the display and print doesn't match
+ the ones implied by the <a href="colprof.html#c">-cmt</a> and <a
+ href="colprof.html#d">-dpp</a> options, leave them out, and
+ evaluate what, if any appearance transformation is appropriate for
+ your environment at a later stage.<br>
+ <br>
+ A fallback to using a specific source profile/gamut is to use a
+ general compression percentage as a gamut mapping:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="file:///D:/src/argyll/doc/colprof.html#S">-S</a><a
+ href="colprof.html#S"> 20</a> <a href="colprof.html#c">-cmt</a> <a
+ href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterA</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the sample data and profile is behaving
+ reasonably. Depending on the type of device, and the consistency of
+ the readings, average errors of 5 or less, and maximum errors of 15
+ or less would normally be expected. If errors are grossly higher
+ than this, then this is an indication that something is seriously
+ wrong with the device measurement, or profile creation.
+ <h4><a name="PP6"></a>Choosing a black generation curve (and other
+ CMYK printer options)<br>
+ </h4>
+ For a CMYK printer, it would be normal to specify the type of black
+ generation, either as something simple, or as a specific curve. The
+ documentation&nbsp; in <a href="colprof.html#k">colprof</a> for the
+ details of the options.<span style="font-weight: bold;"><br>
+ <br>
+ Note</span> that making a good choice of black generation curve
+ can affect things such as: how robust neutrals are given printer
+ drift or changes in viewing lighting, how visible screening is, and
+ how smooth looking the B2A conversion is.<br>
+ <br>
+ For instance, maximizing the level of K will mean that the neutral
+ colors are composed of greater amounts of Black ink, and black ink
+ retains its neutral appearance irrespective of printer behavior or
+ the spectrum of the illuminant used to view the print. On the other
+ hand, output which is dominantly from one of the color channels will
+ tend to emphasize the screening pattern and any unevenness (banding
+ etc.) of that channel, and the black channel in particular has the
+ highest visibility. So in practice, some balance between the levels
+ of the four channels is probably best, with more K if the screening
+ is fine and a robust neutral balance is important, or less K if the
+ screening is more visible and neutral balance is less critical. The
+ levels of K at the edges of the gamut of the device will be fixed by
+ the nature of the ink combinations that maximize the gamut (ie.
+ typically zero ink for light chromatic colors, some combination for
+ dark colors, and a high level of black for very dark near neutrals),
+ and it is also usually important to set a curve that smoothly
+ transitions to the K values at the gamut edges. Dramatic changes in
+ K imply equally dramatic changes in CMY, and these abrupt
+ transitions will reveal the limited precision and detail that can be
+ captured in a lookup table based profile, often resulting in a
+ "bumpy" looking output.<br>
+ <br>
+ If you want to experiment with the various black generation
+ parameters, then it might be a good idea to create a preliminary
+ profile (using <a href="colprof.html#q">-ql</a> <a
+ href="colprof.html#b">-b</a> <a href="colprof.html#ni">-no</a>, <a
href="colprof.html#no">-ni</a> and no <a href="colprof.html#S">-S</a>),
@@ -2196,406 +2269,409 @@ then
- and then used <a href="xicclu.html#g">xicclu</a> to explore the
- effect of the parameters.<br>
- <br>
- For instance, say we have our CMYK .ti3 file <span
- style="font-weight: bold;">PrinterB.ti3</span>. First we make a
- preliminary profile called <span style="font-weight: bold;">PrinterBt</span>:<br>
- <br>
- copy PrinterB.ti3 PrinterBt.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Use
- "cp" on Linux or OSX of course.)<br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#q">-qm</a> <a href="colprof.html#b">-b</a> <a
- href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
- <a href="colprof.html#p1">PrinterBt</a><br>
- <br>
- Then see what the minimum black level down the neutral axis can be.
- Note that we need to also set any ink limits we've decided on as
- well (coloprof defaulting to 10% less than the value recorded in the
- .ti3 file). In this example the test chart has a 300% total ink
- limit, and we've decided to use 290%:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kz</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- Which might be a graph something like this:<br>
- <br>
- <img alt="Graph of CMYK neutral axis with minimum K"
- src="Kgraph1.jpg" style="width: 250px; height: 250px;"><br>
- <br>
- Note&nbsp; how the minimum black is zero up to 93% of the
- white-&gt;black L* curve, and then jumps up to 87%. This is because
- we've reached the total ink limit, and K then has to be substituted
- for CMY, to keep the total under the total ink limit.<br>
- <br>
- Then let's see what the maximum black level down the neutral axis
- can be:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kx</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- Which might be a graph something like this:<br>
- <br>
- <img alt="Graph of CMYK neutral axis with maximum K"
- src="Kgraph2.jpg" style="width: 250px; height: 250px;"><br>
- <br>
- Note how the CMY values are fairly low up to 93% of the
- white-&gt;black L* curve (the low levels of CMY are helping set the
- neutral color), and then they jump up. This is because we've reach
- the point where black on it's own, isn't as dark as the color that
- can be achieved using CMY and K. Because the K has a dominant effect
- on the hue of the black, the levels of CMY are often fairly volatile
- in this region.<br>
- <br>
- Any K curve we specify must lie between the black curves of the
- above two graphs.<br>
- <br>
- Let's say we'd like to chose a moderate black curve, one that aims
- for about equal levels of CMY and K. We should also aim for it to be
- fairly smooth, since this will minimize visual artefacts caused by
- the limited fidelity that profile LUT tables are able to represent
- inside the profile.<br>
- <br>
- <img style="width: 340px; height: 258px;" alt="-k parameters"
- src="Kparams.jpg"><br>
- <br>
- <br>
- For minimum discontinuities we should aim for the curve to finish at
- the point it has to reach to satisfy the total ink limit at 87%
- curve and 93% black. For a first try we can simply set a straight
- line to that point: <br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp 0 0 .93 .87 1.0</a> <a
- href="xicclu.html#l">-l290</a> <a href="xicclu.html#f">-fif</a> <a
- href="xicclu.html#i">-ir</a> <a href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img alt="Graph of CMYK neutral axis with kp 0 0 1.0 1.0 1.0 -l290"
- src="Kgraph3.jpg" style="width: 250px; height: 250px;"><br>
- <br>
- The black "curve" hits the 93%/87% mark well, but is a bit too far
- above CMY, so we'll try making the black curve concave:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
- 0.65</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img alt="Graph of CMYK neutral axis with -kp 0 .05 1 .9 1 -l290"
- src="Kgraph4.jpg" style="width: 250px; height: 249px;"><br>
- <br>
- This looks just about perfect, so the the curve parameters can now
- be used to generate our real profile:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#k">-kp </a><a href="xicclu.html#k">0 0 .93
- .87 0.65</a> <a href="colprof.html#S">-S</a><a
- href="colprof.html#S"> sRGB.icm</a> <a href="colprof.html#c">-cmt</a>
- <a href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterB</a><br>
- <br>
- and the resulting B2A table black curve can be checked using xicclu:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#f">-fb</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterB.icm</a><br>
- <br>
- <img style="width: 250px; height: 250px;" alt="sadsadas"
- src="Kgraph5.jpg"><br>
- <br>
- <br>
- <hr style="margin-left: 0px; margin-right: auto; width: 20%; height:
- 2px;"><br>
- <span style="font-weight: bold;">Examples of other inkings:<br>
- <br>
- </span>A smoothed zero black inking:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 .7 .93 .87
- 1.0</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img style="width: 250px; height: 250px;" alt="sadsadas"
- src="Kgraph6.jpg"><br>
- <br>
- A low black inking:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
- 0.15</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img style="width: 250px; height: 250px;" alt="sadsadas"
- src="Kgraph7.jpg"><br>
- <br>
- <br>
- A high black inking:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
- 1.2</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img style="width: 250px; height: 250px;" alt="sadsadas"
- src="Kgraph8.jpg"><br>
- <br>
- <span style="font-weight: bold;"></span>
- <h4>Overriding the ink limit<br>
- </h4>
- Normally the total ink limit will be read from the <span
- style="font-weight: bold;">PrinterB.ti3</span> file, and will be
- set at a level 10% lower than the number used in creating the test
- chart values using <a href="targen.html#l">targen -l</a>. If you
- want to override this with a lower limit, then use the <a
- href="colprof.html#l">-l flag</a>.<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
- <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
- <a href="colprof.html#k">-kr</a> <a href="xicclu.html#l">-l290</a>
- <a href="colprof.html#p1">PrinterB</a><br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the profile is behaving reasonably.<br>
- <br>
- One way of checking that your ink limit is not too high, is to use "<span
- style="font-weight: bold;">xicc -fif -ia</span>" to check, by
- setting different ink limits using the <span style="font-weight:
- bold;">-l</span> option, feeding Lab = 0 0 0 into it, and checking
- the resulting&nbsp; black point. Starting with the ink limit used
- with <span style="font-weight: bold;">targen</span> for the test
- chart, reduce it until the black point starts to be affected. If it
- is immediately affected by any reduction in the ink limit, then the
- black point may be improved by increasing the ink limit used to
- generate the test chart and then re-print and re-measuring it,
- assuming other aspects such as wetness, smudging, spreading or
- drying time are not an issue.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <h3><a name="PC1"></a>Calibrating Printers<br>
- </h3>
- <span style="font-weight: bold;">Profiling</span> creates a
- description of how a device behaves, while <span
- style="font-weight: bold;">calibration</span> on the other hand is
- intended to <span style="text-decoration: underline;">change</span>
- how a device behaves. Argyll has the ability to create per-channel
- device space calibration curves for print devices, that can then be
- used to improve the behavior of of the device, making a subsequent
- profile fit the device more easily and also allow day to day
- correction of device drift without resorting to a full re-profile.<br>
- <br>
- <span style="font-weight: bold;">NOTE:</span> Because calibration
- adds yet another layer to the way color is processed, it is
- recommended that it not be attempted until the normal profiling
- workflow is established, understood and verified.<br>
- <h4><a name="PC2"></a>Calibrated print workflows</h4>
- There are two main workflows that printer calibration curves can be
- applied to:<br>
- <br>
- <span style="text-decoration: underline;">Workflow <span
- style="font-weight: bold;">with</span> native calibration
- capability</span>:<br>
- <br>
- Firstly the printer itself may have the capability of using per
- channel calibration curves. In this situation, the calibration
- process will be largely independent of profiling. Firstly the
- printer is configured to have both its color management and
- calibration disabled (the latter perhaps achieved by loading linear
- calibration curves), and a print calibration test chart that
- consists of per channel color wedges is printed. The calibration
- chart is read and the resulting .ti3 file converted into calibration
- curves by processing it using <span style="font-weight: bold;">printcal</span>.
- The calibration is then installed into the printer. Subsequent
- profiling will be performed on the <span style="text-decoration:
- underline;">calibrated</span> printer (ie. the profile test chart
- will have the calibration curves applied to it by the printer, and
- the resulting ICC profile will represent the behavior of the
- calibrated printer.)<br>
- <br>
- <span style="text-decoration: underline;">Workflow <span
- style="font-weight: bold;">without</span> native calibration
- capability</span>:<br>
- <br>
- The second workflow is one in which the printer has no calibration
- capability itself. In this situation, the calibration process will
- have to be applied using the ICC color management tools, so careful
- coordination with profiling is needed. Firstly the printer is
- configured to have its color management disabled, and a print
- calibration test chart that consists of per channel color wedges is
- printed. The calibration chart is converted into calibration curves
- by reading it and then processing the resultant .ti3 using <span
- style="font-weight: bold;">printcal</span>,. During the subsequent
- <span style="text-decoration: underline;">profiling</span>, the
- calibration curves will need to be applied to the profile test chart
- in the process of using <span style="font-weight: bold;">printtarg</span>.
- Once the the profile has been created, then in subsequent printing
- the calibration curves will need to be applied to an image being
- printed either explicitly when using <span style="font-weight:
- bold;">cctiff</span> to apply color profiles <span
- style="text-decoration: underline;">and</span> calibration, <span
- style="font-weight: bold;">OR</span> by creating a version of the
- profile that has had the calibration curves incorporated into it
- using the <span style="font-weight: bold;">applycal</span> tool.
- The latter is useful when some CMM (color management module) other
- than <span style="font-weight: bold;">cctiff </span>is being used.<br>
- <br>
- Once calibration aim targets for a particular device and mode
- (screening, paper etc.) have been established, then the printer can
- be re-calibrated at any time to bring its per channel behavior back
- into line if it drifts, and the new calibration curves can be
- installed into the printer, or re-incorporated into the profile.
- &nbsp;
- <h4><a name="PC3"></a>Creating a print calibration test chart</h4>
- The first step is to create a print calibration test chart. Since
- calibration only creates per-channel curves, only single channel
- step wedges are required for the chart. The main choice is the
- number of steps in each wedge. For simple fast calibrations perhaps
- as few as 20 steps per channel may be enough, but for a better
- quality of calibration something like 50 or more steps would be a
- better choice.<br>
- <br>
- Let's consider two devices in our examples, "PrinterA" which is an
- "RGB" printer device, and "PrinterB" which is CMYK. In fact there is
- no such thing as a real RGB printer, since printers use white media
- and the colorant must subtract from the light reflected on it to
- create color, but the printer itself turns the incoming RGB into the
- native print colorspace, so for this reason we are careful to tell
- targen to use the "Print RGB" colorspace, so that it knows to create
- step wedges from media white to full colorant values.<br>
- <br>
- For instance, to create a 50 steps per channel calibration test
- chart for our RGB and CMYK devices, the following would be
- sufficient:<br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#s">-s50</a>
- <a href="targen.html#e">-e3</a> <a href="targen.html#f">-f0</a> <a
- href="targen.html#p1">PrinterA_c</a><br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#s">-s50</a>
- <a href="targen.html#e">-e4</a> <a href="targen.html#f">-f0</a> <a
- href="targen.html#p1">PrinterB_c</a><br>
- <a href="targen.html#p1"></a><br>
- For an outline of how to then print and read the resulting test
- chart, see&nbsp; <a href="Scenarios.html#PP2b">Printing a print
- profile test chart</a>, and <a href="Scenarios.html#PP3">Reading
- a print test chart using an instrument</a>. Note that the printer
- must be in an un-profiled and un-calibrated mode when doing this
- print. Having done this, there will be a PrinterA.ti3 or
- PrinterB.ti3 file containing the step wedge calibration chart
- readings.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that if you are
- calibrating a raw printer driver, and there is considerable dot
- gain, then you may want to use the <a href="targen.html#p">-p</a>
- parameter to adjust the test chart point distribution to spread them
- more evenly in perceptual space, giving more accurate control over
- the calibration. Typically this will be a value greater than one for
- a device that has dot gain, e.g. values of 1.5, 2.0 or 2.5 might be
- good places to start. You can do a preliminary calibration and use
- the verbose output of printcal to recommend a suitable value for <span
- style="font-weight: bold;">-p</span>.<br>
- <h4><a name="PC4"></a>Creating a printer calibration<br>
- </h4>
- The <a href="printcal.html">printcal</a> tool turns a calibration
- chart <a href="File_Formats.html#.ti3">.ti3</a> file into a <a
- href="File_Formats.html#.cal">.cal</a> file. It has three main
- operating modes:- Initial calibration, Re-Calibration, and
- Verification. (A fourth mode, "Imitation" is very like Initial
- Calibration, but is used for establishing a calibration target that
- a similar printer can attempt to imitate.)<br>
- <br>
- The distinction between Initial Calibration and Re-Calibration is
- that in the initial calibration we establish the "aim points" or
- response we want out of the printer after calibration. There are
- three basic parameters to set this for each channel: Maximum level,
- minimum level, and curve shape.<br>
- <br>
- By default the maximum level will be set using a heuristic which
- attempts to pick the point when there is diminishing returns for
- applying more colorant. This can be overridden using the <span
- style="font-weight: bold;">-x# percent</span> option, where <span
- style="font-weight: bold;">#</span> represents the choice of
- channel this will be applied to. The parameter is the percentage of
- device maximum. <br>
- <br>
- The minimum level defaults to 0, but can be overridden using the <span
- style="font-weight: bold;">-n# deltaE</span> option. A minimum of
- 0 means that zero colorant will correspond to the natural media
- color, but it may be desirable to set a non-pure media color using
- calibration for the purposes of emulating some other media. The
- parameter is in Delta E units.<br>
- <br>
- The curve shape defaults to being perceptually uniform, which means
- that even steps of calibrated device value result in perceptually
- even color steps. In some situations it may be desirable to alter
- this curve (for instance when non color managed output needs to be
- sent to the calibrated printer), and a simple curve shape target can
- be set using the <span style="font-weight: bold;">-t# percent</span>
- parameter. This affects the output value at 50% input value, and
- represents the percentage of perceptual output. By default it is 50%
- perceptual output for 50% device input.<br>
- <br>
- Once a device has been calibrated, it can be re-calibrated to the
- same aim target.<br>
- <br>
- Verification uses a calibration test chart printed through the
- calibration, and compares the achieved response to the aim target.<br>
- <br>
- The simplest possible way of creating the <span style="font-weight:
- bold;">PrinterA.cal</span> file is:<br>
- <br>
- &nbsp; <a href="printcal.html">printcal</a> <a
- href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterA_c</a><br>
- <br>
- For more detailed information, you can add the <span
- style="font-weight: bold;">-v</span> and <span
- style="font-weight: bold;">-p</span> flags:<br>
- <br>
- &nbsp; <a href="printcal.html">printcal</a> <a
- href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
- href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterB_c</a><br>
- <br>
- (You will need to select the plot window and hit a key to advance
- past each plot).<br>
- <br>
- For re-calibration, the name of the previous calibration file will
- need to be supplied, and a new calibration<br>
- file will be created:<br>
- <br>
- &nbsp; <a href="printcal.html">printcal</a> <a
- href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
- href="printcal.html#r">-r</a> <a href="colprof.html#p1">PrinterB_c_old</a>
- <a href="colprof.html#p2">PrinterB_c_new</a><br>
- <br>
- Various aim points are normally set automatically by <span
- style="font-weight: bold;">printcal</span>, but these can be
- overridden using the <a href="colprof.html#x">-x</a>, <a
- href="colprof.html#n">-n</a> and <a href="colprof.html#t">-t</a>
- options. e.g. say we wanted to set the maximum ink for Cyan to 80%
- and Black to 95%, we might use:<br>
- <br>
- &nbsp; <a href="printcal.html">printcal</a> <a
- href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
- href="printcal.html#i">-i</a> <a href="colprof.html#x">-xc 80</a>
- <a href="colprof.html#x">-xk 95</a> <a href="colprof.html#p2">PrinterB_c</a><br>
- <br>
- <a href="colprof.html#p2"></a>
- <h4><a name="PC5"></a>Using a printer calibration</h4>
- The resulting calibration curves can be used with the following
- other Argyll tools:<br>
- <br>
+
+
+
+ and then used <a href="xicclu.html#g">xicclu</a> to explore the
+ effect of the parameters.<br>
+ <br>
+ For instance, say we have our CMYK .ti3 file <span
+ style="font-weight: bold;">PrinterB.ti3</span>. First we make a
+ preliminary profile called <span style="font-weight: bold;">PrinterBt</span>:<br>
+ <br>
+ copy PrinterB.ti3 PrinterBt.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Use
+ "cp" on Linux or OSX of course.)<br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#q">-qm</a> <a href="colprof.html#b">-b</a> <a
+ href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#p1">PrinterBt</a><br>
+ <br>
+ Then see what the minimum black level down the neutral axis can be.
+ Note that we need to also set any ink limits we've decided on as
+ well (coloprof defaulting to 10% less than the value recorded in the
+ .ti3 file). In this example the test chart has a 300% total ink
+ limit, and we've decided to use 290%:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kz</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ Which might be a graph something like this:<br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with minimum K"
+ src="Kgraph1.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ Note&nbsp; how the minimum black is zero up to 93% of the
+ white-&gt;black L* curve, and then jumps up to 87%. This is because
+ we've reached the total ink limit, and K then has to be substituted
+ for CMY, to keep the total under the total ink limit.<br>
+ <br>
+ Then let's see what the maximum black level down the neutral axis
+ can be:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kx</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ Which might be a graph something like this:<br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with maximum K"
+ src="Kgraph2.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ Note how the CMY values are fairly low up to 93% of the
+ white-&gt;black L* curve (the low levels of CMY are helping set the
+ neutral color), and then they jump up. This is because we've reach
+ the point where black on it's own, isn't as dark as the color that
+ can be achieved using CMY and K. Because the K has a dominant effect
+ on the hue of the black, the levels of CMY are often fairly volatile
+ in this region.<br>
+ <br>
+ Any K curve we specify must lie between the black curves of the
+ above two graphs.<br>
+ <br>
+ Let's say we'd like to chose a moderate black curve, one that aims
+ for about equal levels of CMY and K. We should also aim for it to be
+ fairly smooth, since this will minimize visual artefacts caused by
+ the limited fidelity that profile LUT tables are able to represent
+ inside the profile.<br>
+ <br>
+ <img style="width: 340px; height: 258px;" alt="-k parameters"
+ src="Kparams.jpg"><br>
+ <br>
+ <br>
+ For minimum discontinuities we should aim for the curve to finish at
+ the point it has to reach to satisfy the total ink limit at 87%
+ curve and 93% black. For a first try we can simply set a straight
+ line to that point: <br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp 0 0 .93 .87 1.0</a> <a
+ href="xicclu.html#l">-l290</a> <a href="xicclu.html#f">-fif</a> <a
+ href="xicclu.html#i">-ir</a> <a href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with kp 0 0 1.0 1.0 1.0 -l290"
+ src="Kgraph3.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ The black "curve" hits the 93%/87% mark well, but is a bit too far
+ above CMY, so we'll try making the black curve concave:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 0.65</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with -kp 0 .05 1 .9 1 -l290"
+ src="Kgraph4.jpg" style="width: 250px; height: 249px;"><br>
+ <br>
+ This looks just about perfect, so the the curve parameters can now
+ be used to generate our real profile:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#k">-kp </a><a href="xicclu.html#k">0 0 .93
+ .87 0.65</a> <a href="colprof.html#S">-S</a><a
+ href="colprof.html#S"> sRGB.icm</a> <a href="colprof.html#c">-cmt</a>
+ <a href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterB</a><br>
+ <br>
+ and the resulting B2A table black curve can be checked using xicclu:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#f">-fb</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterB.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph5.jpg"><br>
+ <br>
+ <br>
+ <hr style="margin-left: 0px; margin-right: auto; width: 20%; height:
+ 2px;"><br>
+ <span style="font-weight: bold;">Examples of other inkings:<br>
+ <br>
+ </span>A smoothed zero black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 .7 .93 .87
+ 1.0</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph6.jpg"><br>
+ <br>
+ A low black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 0.15</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph7.jpg"><br>
+ <br>
+ <br>
+ A high black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 1.2</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph8.jpg"><br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <h4>Overriding the ink limit<br>
+ </h4>
+ Normally the total ink limit will be read from the <span
+ style="font-weight: bold;">PrinterB.ti3</span> file, and will be
+ set at a level 10% lower than the number used in creating the test
+ chart values using <a href="targen.html#l">targen -l</a>. If you
+ want to override this with a lower limit, then use the <a
+ href="colprof.html#l">-l flag</a>.<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
+ <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#k">-kr</a> <a href="xicclu.html#l">-l290</a>
+ <a href="colprof.html#p1">PrinterB</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the profile is behaving reasonably.<br>
+ <br>
+ One way of checking that your ink limit is not too high, is to use "<span
+ style="font-weight: bold;">xicc -fif -ia</span>" to check, by
+ setting different ink limits using the <span style="font-weight:
+ bold;">-l</span> option, feeding Lab = 0 0 0 into it, and checking
+ the resulting&nbsp; black point. Starting with the ink limit used
+ with <span style="font-weight: bold;">targen</span> for the test
+ chart, reduce it until the black point starts to be affected. If it
+ is immediately affected by any reduction in the ink limit, then the
+ black point may be improved by increasing the ink limit used to
+ generate the test chart and then re-print and re-measuring it,
+ assuming other aspects such as wetness, smudging, spreading or
+ drying time are not an issue.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <h3><a name="PC1"></a>Calibrating Printers<br>
+ </h3>
+ <span style="font-weight: bold;">Profiling</span> creates a
+ description of how a device behaves, while <span
+ style="font-weight: bold;">calibration</span> on the other hand is
+ intended to <span style="text-decoration: underline;">change</span>
+ how a device behaves. Argyll has the ability to create per-channel
+ device space calibration curves for print devices, that can then be
+ used to improve the behavior of of the device, making a subsequent
+ profile fit the device more easily and also allow day to day
+ correction of device drift without resorting to a full re-profile.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE:</span> Because calibration
+ adds yet another layer to the way color is processed, it is
+ recommended that it not be attempted until the normal profiling
+ workflow is established, understood and verified.<br>
+ <h4><a name="PC2"></a>Calibrated print workflows</h4>
+ There are two main workflows that printer calibration curves can be
+ applied to:<br>
+ <br>
+ <span style="text-decoration: underline;">Workflow <span
+ style="font-weight: bold;">with</span> native calibration
+ capability</span>:<br>
+ <br>
+ Firstly the printer itself may have the capability of using per
+ channel calibration curves. In this situation, the calibration
+ process will be largely independent of profiling. Firstly the
+ printer is configured to have both its color management and
+ calibration disabled (the latter perhaps achieved by loading linear
+ calibration curves), and a print calibration test chart that
+ consists of per channel color wedges is printed. The calibration
+ chart is read and the resulting .ti3 file converted into calibration
+ curves by processing it using <span style="font-weight: bold;">printcal</span>.
+ The calibration is then installed into the printer. Subsequent
+ profiling will be performed on the <span style="text-decoration:
+ underline;">calibrated</span> printer (ie. the profile test chart
+ will have the calibration curves applied to it by the printer, and
+ the resulting ICC profile will represent the behavior of the
+ calibrated printer.)<br>
+ <br>
+ <span style="text-decoration: underline;">Workflow <span
+ style="font-weight: bold;">without</span> native calibration
+ capability</span>:<br>
+ <br>
+ The second workflow is one in which the printer has no calibration
+ capability itself. In this situation, the calibration process will
+ have to be applied using the ICC color management tools, so careful
+ coordination with profiling is needed. Firstly the printer is
+ configured to have its color management disabled, and a print
+ calibration test chart that consists of per channel color wedges is
+ printed. The calibration chart is converted into calibration curves
+ by reading it and then processing the resultant .ti3 using <span
+ style="font-weight: bold;">printcal</span>,. During the subsequent
+ <span style="text-decoration: underline;">profiling</span>, the
+ calibration curves will need to be applied to the profile test chart
+ in the process of using <span style="font-weight: bold;">printtarg</span>.
+ Once the the profile has been created, then in subsequent printing
+ the calibration curves will need to be applied to an image being
+ printed either explicitly when using <span style="font-weight:
+ bold;">cctiff</span> to apply color profiles <span
+ style="text-decoration: underline;">and</span> calibration, <span
+ style="font-weight: bold;">OR</span> by creating a version of the
+ profile that has had the calibration curves incorporated into it
+ using the <span style="font-weight: bold;">applycal</span> tool.
+ The latter is useful when some CMM (color management module) other
+ than <span style="font-weight: bold;">cctiff </span>is being used.<br>
+ <br>
+ Once calibration aim targets for a particular device and mode
+ (screening, paper etc.) have been established, then the printer can
+ be re-calibrated at any time to bring its per channel behavior back
+ into line if it drifts, and the new calibration curves can be
+ installed into the printer, or re-incorporated into the profile.
+ &nbsp;
+ <h4><a name="PC3"></a>Creating a print calibration test chart</h4>
+ The first step is to create a print calibration test chart. Since
+ calibration only creates per-channel curves, only single channel
+ step wedges are required for the chart. The main choice is the
+ number of steps in each wedge. For simple fast calibrations perhaps
+ as few as 20 steps per channel may be enough, but for a better
+ quality of calibration something like 50 or more steps would be a
+ better choice.<br>
+ <br>
+ Let's consider two devices in our examples, "PrinterA" which is an
+ "RGB" printer device, and "PrinterB" which is CMYK. In fact there is
+ no such thing as a real RGB printer, since printers use white media
+ and the colorant must subtract from the light reflected on it to
+ create color, but the printer itself turns the incoming RGB into the
+ native print colorspace, so for this reason we are careful to tell
+ targen to use the "Print RGB" colorspace, so that it knows to create
+ step wedges from media white to full colorant values.<br>
+ <br>
+ For instance, to create a 50 steps per channel calibration test
+ chart for our RGB and CMYK devices, the following would be
+ sufficient:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#s">-s50</a>
+ <a href="targen.html#e">-e3</a> <a href="targen.html#f">-f0</a> <a
+ href="targen.html#p1">PrinterA_c</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#s">-s50</a>
+ <a href="targen.html#e">-e4</a> <a href="targen.html#f">-f0</a> <a
+ href="targen.html#p1">PrinterB_c</a><br>
+ <a href="targen.html#p1"></a><br>
+ For an outline of how to then print and read the resulting test
+ chart, see&nbsp; <a href="Scenarios.html#PP2b">Printing a print
+ profile test chart</a>, and <a href="Scenarios.html#PP3">Reading
+ a print test chart using an instrument</a>. Note that the printer
+ must be in an un-profiled and un-calibrated mode when doing this
+ print. Having done this, there will be a PrinterA.ti3 or
+ PrinterB.ti3 file containing the step wedge calibration chart
+ readings.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you are
+ calibrating a raw printer driver, and there is considerable dot
+ gain, then you may want to use the <a href="targen.html#p">-p</a>
+ parameter to adjust the test chart point distribution to spread them
+ more evenly in perceptual space, giving more accurate control over
+ the calibration. Typically this will be a value greater than one for
+ a device that has dot gain, e.g. values of 1.5, 2.0 or 2.5 might be
+ good places to start. You can do a preliminary calibration and use
+ the verbose output of printcal to recommend a suitable value for <span
+ style="font-weight: bold;">-p</span>.<br>
+ <h4><a name="PC4"></a>Creating a printer calibration<br>
+ </h4>
+ The <a href="printcal.html">printcal</a> tool turns a calibration
+ chart <a href="File_Formats.html#.ti3">.ti3</a> file into a <a
+ href="File_Formats.html#.cal">.cal</a> file. It has three main
+ operating modes:- Initial calibration, Re-Calibration, and
+ Verification. (A fourth mode, "Imitation" is very like Initial
+ Calibration, but is used for establishing a calibration target that
+ a similar printer can attempt to imitate.)<br>
+ <br>
+ The distinction between Initial Calibration and Re-Calibration is
+ that in the initial calibration we establish the "aim points" or
+ response we want out of the printer after calibration. There are
+ three basic parameters to set this for each channel: Maximum level,
+ minimum level, and curve shape.<br>
+ <br>
+ By default the maximum level will be set using a heuristic which
+ attempts to pick the point when there is diminishing returns for
+ applying more colorant. This can be overridden using the <span
+ style="font-weight: bold;">-x# percent</span> option, where <span
+ style="font-weight: bold;">#</span> represents the choice of
+ channel this will be applied to. The parameter is the percentage of
+ device maximum. <br>
+ <br>
+ The minimum level defaults to 0, but can be overridden using the <span
+ style="font-weight: bold;">-n# deltaE</span> option. A minimum of
+ 0 means that zero colorant will correspond to the natural media
+ color, but it may be desirable to set a non-pure media color using
+ calibration for the purposes of emulating some other media. The
+ parameter is in Delta E units.<br>
+ <br>
+ The curve shape defaults to being perceptually uniform, which means
+ that even steps of calibrated device value result in perceptually
+ even color steps. In some situations it may be desirable to alter
+ this curve (for instance when non color managed output needs to be
+ sent to the calibrated printer), and a simple curve shape target can
+ be set using the <span style="font-weight: bold;">-t# percent</span>
+ parameter. This affects the output value at 50% input value, and
+ represents the percentage of perceptual output. By default it is 50%
+ perceptual output for 50% device input.<br>
+ <br>
+ Once a device has been calibrated, it can be re-calibrated to the
+ same aim target.<br>
+ <br>
+ Verification uses a calibration test chart printed through the
+ calibration, and compares the achieved response to the aim target.<br>
+ <br>
+ The simplest possible way of creating the <span style="font-weight:
+ bold;">PrinterA.cal</span> file is:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterA_c</a><br>
+ <br>
+ For more detailed information, you can add the <span
+ style="font-weight: bold;">-v</span> and <span
+ style="font-weight: bold;">-p</span> flags:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterB_c</a><br>
+ <br>
+ (You will need to select the plot window and hit a key to advance
+ past each plot).<br>
+ <br>
+ For re-calibration, the name of the previous calibration file will
+ need to be supplied, and a new calibration<br>
+ file will be created:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#r">-r</a> <a href="colprof.html#p1">PrinterB_c_old</a>
+ <a href="colprof.html#p2">PrinterB_c_new</a><br>
+ <br>
+ Various aim points are normally set automatically by <span
+ style="font-weight: bold;">printcal</span>, but these can be
+ overridden using the <a href="colprof.html#x">-x</a>, <a
+ href="colprof.html#n">-n</a> and <a href="colprof.html#t">-t</a>
+ options. e.g. say we wanted to set the maximum ink for Cyan to 80%
+ and Black to 95%, we might use:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#x">-xc 80</a>
+ <a href="colprof.html#x">-xk 95</a> <a href="colprof.html#p2">PrinterB_c</a><br>
+ <br>
+ <a href="colprof.html#p2"></a>
+ <h4><a name="PC5"></a>Using a printer calibration</h4>
+ The resulting calibration curves can be used with the following
+ other Argyll tools:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="printtarg.html#K">printtarg</a>&nbsp;&nbsp;&nbsp;&nbsp;
To
apply
@@ -2664,7 +2740,10 @@ chart,
- and/or to have it included in .ti3 file.<br>
+
+
+
+ and/or to have it included in .ti3 file.<br>
&nbsp;&nbsp;&nbsp; <a href="cctiff.html#p2">cctiff</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
To
apply
@@ -2733,7 +2812,10 @@ an
- image file.<br>
+
+
+
+ image file.<br>
&nbsp;&nbsp;&nbsp; <a href="applycal.html#p1">applycal</a>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2794,7 +2876,10 @@ an
- To incorporate calibration into an ICC profile.<br>
+
+
+
+ To incorporate calibration into an ICC profile.<br>
&nbsp;&nbsp;&nbsp; <a href="chartread.html#I">chartread</a>&nbsp;&nbsp;
To
override
@@ -2863,349 +2948,346 @@ a
- profile chart.<br>
- <br>
- <br>
- In a workflow <span style="font-weight: bold;">with</span> native
- calibration capability, the calibration curves would be used with
- printarg during subsequent <span style="font-weight: bold;">profiling</span>
- so that any ink limit calculations will reflect final device values,
- while not otherwise using the calibration within the ICC workflow:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
- href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
- <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#I">-I
- PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
- <br>
- This will cause the .ti2 and resulting .ti3 and ICC profiles to
- contain the calibration curves, allowing all the tools to be able to
- compute final device value ink limits. The calibration curves must
- also of course be installed into the printer. The means to do this
- is currently outside the scope of Argyll (ie. either the print
- system needs to be able to understand Argyll CAL format files, or
- some tool will be needed to convert Argyll CAL files into the
- printer calibration format).<br>
- <br>
- <br>
- In a workflow <span style="font-weight: bold;">without</span>
- native calibration capability, the calibration curves would be used
- with printarg to <span style="text-decoration: underline;">apply</span>
- the calibration to the test patch samples during subsequent <span
- style="font-weight: bold;">profiling</span>, as well as embedding
- it in the resulting .ti3 to allow all the tools to be able to
- compute final device value ink limits:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
- href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
- <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#K">-K
- PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
- <a href="cctiff.html#p4"></a><br>
- To apply calibration to an ICC profile, so that a calibration
- unaware CMM can be used:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="applycal.html">applycal</a> <a
- href="applycal.html#p1">PrinterA.cal</a> <a
- href="applycal.html#p2">PrinterA.icm</a> <a
- href="applycal.html#p3">PrinterA_cal.icm</a><br>
- <br>
- To apply color management and calibration to a raster image:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a>
- <a href="cctiff.html#p1">Source.icm</a> <a
- href="cctiff.html#p1">PrinterA.icm</a> <a
- href="cctiff.html#p2">PrinterA_c.cal</a>
- <a href="cctiff.html#p3">infile.tif</a> <a
- href="cctiff.html#p4">outfile.tif</a><br>
- <br>
- or<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a>
- <a href="cctiff.html#p1">Source.icm</a> <a
- href="cctiff.html#p1">PrinterA_c.icm</a>
- <a href="cctiff.html#p3">infile.tif</a> <a
- href="cctiff.html#p4">outfile.tif</a><br>
- <br>
- [ Note that cctiff will also process JPEG raster images. ]<br>
- <br>
- Another useful tool is <a href="synthcal.html">synthcal</a>, that
- allows creating linear or synthetic calibration files for disabling
- calibration or testing.<br>
- Similarly, <a href="fakeread.html">fakeread</a> also supports
- applying calibration curves and embedding them in the resulting .ti3
- file<br>
- <br>
- If you want to create a pre-conditioning profile for use with <a
- href="targen.html#c">targen -c</a>, then use the PrinterA.icm
- profile, <b>NOT</b> PrinterA_c.icm that has calibration curves
- applied.<br>
- <h4><a name="PC6"></a>How profile ink limits are handled when
- calibration is being used.</h4>
- Even though the profiling process is carried out on top of the
- linearized device, and the profiling is generally unaware of the
- underlying non-linearized device values, an exception is made in the
- calculation of ink limits during profiling. This is made possible by
- including the calibration curves in the profile charts .ti2 and
- subsequent .ti3 file and resulting ICC profile <span
- style="font-weight: bold;">'targ'</span> text tag, by way of the <span
- style="font-weight: bold;">printtarg</span> <span
- style="font-weight: bold;">-I</span> or <span style="font-weight:
- bold;">-K</span> options. This is done on the assumption that the
- physical quantity of ink is what's important in setting the ink
- limit, and that the underlying non-linearized device values
- represent such a physical quantity.<br>
- <br>
- <br>
- <hr size="2" width="100%">
- <h3><a name="LP1"></a>Linking Profiles</h3>
- Two device profiles can be linked together to create a device link
- profile, than encapsulates a particular device to device transform.
- Often this step is not necessary, as many systems and tools will
- link two device profiles "on the fly", but creating a device link
- profile gives you the option of using "smart CMM" techniques, such
- as true gamut mapping, improved inverse transform accuracy, tailored
- black generation and ink limiting.<br>
- <br>
- The overall process is to link the input space and output space
- profiles using <a href="collink.html">collink</a>, creating a
- device to device link profile. The device to device link profile can
- then be used by cctiff (or other ICC device profile capable tools),
- to color correct a raster files.<br>
- <br>
- Three examples will be given here, showing the three different modes
- than <span style="font-weight: bold;">collink</span> supports.<br>
- <br>
- In <a href="collink.html#s">simple mode</a>, the two profiles are
- linked together in a similar fashion to other <span
- style="font-weight: bold;">CMMs</span> simply using the forward
- and backwards color transforms defined by the profiles. Any gamut
- mapping is determined by the content of the tables within the two
- profiles, together with the particular intent chosen. Typically the
- same intent will be used for both the source and destination
- profile:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#s">-s</a> <a
- href="collink.html#si">-ip</a> <a href="collink.html#so">-op</a>
- <a href="collink.html#p1">SouceProfile.icm</a> <a
- href="collink.html#p2">DestinationProfile.icm</a> <a
- href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- <br>
- In <a href="collink.html#g">gamut mapping mode</a>, the
- pre-computed intent mappings inside the profiles are not used, but
- instead the gamut mapping between source and destination is tailored
- to the specific gamuts of the two profiles, and the intent parameter
- supplied to <span style="font-weight: bold;">collink</span>.
- Additionally, source and destination viewing conditions should be
- provided, to allow the color appearance space conversion to work as
- intended. The colorimetric B2A table in the destination profile is
- used, and this will determine any black generation and ink limiting:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#g">-g</a> <a
- href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
- <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
- <a href="collink.html#p2">DestinationProfile.icm</a> <a
- href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- [ If your viewing environment for the display and print doesn't
- match the ones implied by the <a href="colprof.html#c">-cmt</a> and
- <a href="colprof.html#d">-dpp</a> options, leave them out, and
- evaluate what, if any appearance transformation is appropriate for
- your environment at a later stage. ]<br>
- <br>
- In <a href="collink.html#G">inverse output table gamut mapping mode</a>,
- the pre-computed intent mappings inside the profiles are not used,
- but instead the gamut mapping between source and destination is
- tailored to the specific gamuts of the two profiles, and the intent
- parameter supplied to <span style="font-weight: bold;">collink</span>.
- In addition, the B2A table is <span style="font-weight: bold;">not</span>
- used in the destination profile, but the A2B table is instead
- inverted, leading to improved transform accuracy, and in CMYK
- devices, allowing the ink limiting and black generation parameters
- to be set:<br>
- <br>
- For a CLUT table based RGB printer destination profile, the
- following would be appropriate:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
- href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
- <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
- <a href="collink.html#p2">RGBDestinationProfile.icm</a> <a
- href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- For a CMYK profile, the total ink limit needs to be specified (a
- typical value being 10% less than the value used in creating the
- device test chart), and the type of black generation also needs to
- be specified:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
- href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
- <a href="collink.html#d">-dpp</a> <a href="collink.html#l">-l250</a>
- <a href="collink.html#k">-kr</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
- <a href="collink.html#p2">CMYKDestinationProfile.icm</a> <a
- href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- Note that you should set the source (<a href="collink.html#c">-c</a>)
- and destination (<a href="collink.html#d">-d</a>) viewing conditions
- for the type of device the profile represents, and the conditions
- under which it will be viewed.<br>
- <br>
- <h3><a name="LP3"></a>Image dependent gamut mapping using device
- links<br>
- </h3>
- When images are stored in large gamut colorspaces (such as. L*a*b*,
- ProPhoto, scRGB etc.), then using the colorspace gamut as the source
- gamut for gamut mapping is generally a bad idea, as it leads to
- overly compressed and dull images. The correct approach is to use a
- source gamut that represents the gamut of the images themselves.
- This can be created using tiffgamut, and an example workflow is as
- follows:<br>
- <br>
- <a href="tiffgamut.html">tiffgamut</a> -f80 -pj -cmt ProPhoto.icm
- image.tif<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qh</a> <a href="collink.html#G">-G</a> <a
- href="collink.html#Gp">image.gam</a> <a href="collink.html#si">-ip</a>
- <a href="collink.html#c">-cmt</a> <a href="collink.html#d">-dpp</a>
- <a href="collink.html#p1">ProPhoto.icm</a> <a
- href="collink.html#p2">RGBDestinationProfile.icm</a>
- <a href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- <a href="cctiff.html">cctiff</a> <a
- href="cctiff.html#p1">Source2Destination.icm</a>
- <a href="cctiff.html#p3">image.tif</a> <a
- href="cctiff.html#p4">printfile.tif</a><br>
- <br>
- The printfile.tif is then send to the printer without color
- management, (i.e. in the same way the printer characterization test
- chart was printed), since it is in the printers native colorspace.<br>
- <br>
- You can adjust how conservatively the image gamut is preserved using
- the tiffgamut -f parameter. Omitting it or using a larger value (up
- to 100) preserves the color gradations of even the lesser used
- colors, at the cost of compressing the gamut more.<br>
- Using a smaller value will preserve the saturation of the most
- popular colors, at the cost of not preserving the color gradations
- of less popular colors.<br>
- <br>
- You can create a gamut that covers a set of source images by
- providing more than one image file name to tiffgamut. This may be
- more efficient for a group of related images, and ensures that
- colors are transformed in exactly the same way for all of the
- images.<br>
- <br>
- An alternative generating a gamut for a specific set of images, is
- to use a general smaller gamut definition (i.e. the sRGB profile),
- or a gamut that represents the typical range of colors you wish to
- preserve.<br>
- <br>
- The arguments to collink should be appropriate for the output device
- type - see the collink examples in the above section.<br>
- <h3><a name="LP2"></a>Soft Proofing Link</h3>
- Often it is desirable to get an idea what a particular devices
- output will look like using a different device. Typically this might
- be trying to evaluate print output using a display. Often it is
- sufficient to use an absolute or relative colorimetric transform
- from the print device space to the display space, but while these
- provide a colorimetric preview of the result, they do not take into
- account the subjective appearance differences due to the different
- device conditions. It can therefore be useful to create a soft proof
- appearance transform using collink:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
- href="collink.html#si">-ila</a> <a href="collink.html#c">-cpp</a>
- <a href="collink.html#d">-dmt</a> <a href="collink.html#l">-t250</a>&nbsp;<a
- href="collink.html#k"></a><a href="collink.html#p1">CMYKDestinationProfile.icm</a>
- <a href="collink.html#p2">MonitorProfile.icm</a> <a
- href="collink.html#p3">SoftProof.icm</a><br>
- <br>
- We use the Luminance matched appearance intent, to preserve the
- subjective apperance of the target device, which takes into account
- the viewing conditions and assumes adaptation to the differences in
- the luminence range, but otherwise not attempting to compress or
- change the gamut.<br>
- <br>
- If your viewing environment for the display and print doesn't match
- the ones implied by the <a href="collink.html#c">-cpp</a> and <a
- href="collink.html#d">-dmt</a> options, then either leave them out
- or substitute values that do match your environment.<br>
- &nbsp;
- <hr size="2" width="100%"><br>
- <h3><a name="TR1"></a>Transforming colorspaces of raster files</h3>
- Although a device profile or device link profile may be useful with
- other programs and systems, Argyll provides the tool <a
- href="cctiff.html">cctiff</a> for directly applying a device to
- device transform to a <a href="File_Formats.html#TIFF">TIFF</a> or
- <a href="File_Formats.html#JPEG">JPEG</a> raster file. The cctiff
- tool is capable of linking an arbitrary sequence of device profiles,
- device links, abstract profiles and calibration curves. Each device
- profile can be preceded by the <span style="font-weight: bold;">-i</span>
- option to indicate the intent that should be used. Both 8 and 16 bit
- per component files can be handled, and up to 8 color channels. The
- color transform is optimized to perform the overall transformation
- rapidly.<br>
- <br>
- If a device link is to be used, the following is a typical example:<br>
- <br>
- <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
- <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
- or<br>
- <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
- <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
- <br>
- <i><br>
- </i>If a source and destination profile are to be used, the
- following would be a typical example:<br>
- <br>
- <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
- <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
- href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
- <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
- or<br>
- <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
- <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
- href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
- <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
- <br>
- <br>
- <hr size="2" width="100%"><br>
- <h3><a name="TV1"></a>Creating Video Calibration 3DLuts</h3>
- Video calibration typically involves trying to make your actual
- display device emulate an ideal video display, one which matches
- what your Video media was intended to be displayed on. An ICC device
- link embodies the machinery to do exactly this, to take device
- values in the target source colorspace and transform them into an
- actual output device colorspace. In the Video and Film industries a
- very similar, but less sophisticated means of doing this is to use
- 3DLuts, which come in a multitude of different format. ICC device
- links have the advantage of being a superset of 3dLuts, encapsulated
- in a standard file format.<br>
- <br>
- To facilitate Video calibration of certain Video systems, ArgyllCMS
- supports some 3DLut output options as part of <a
- href="collink.html">collink</a>.<br>
- <br>
- What follows here is an outline of how to create Video calibration
- 3DLuts using ArgyllCMS. First comes a general discussion of various
- aspects of video device links/3dLuts, and followed with some
- specific advice regarding the systems that ArgyllCMS supports. Last
- is some recommended scenarios for verifying the quality of Video
- calibration achieved.<br>
- <h5>1) How to display test patches.<br>
- </h5>
- Argyll's normal test patch display will be used by default, as long
- as any video encoding range considerations are dealt with (see
- Signal encoding below).<br>
- <br>
- An alternative when working with MadVR V 0.86.9 or latter, is to use
- the madTPG to display the patches in which case the MadVR video
- encoding range setting will operate. This can give some quality
- benefits due to MadVR's use of dithering. To display patches using
+
+
+
+ profile chart.<br>
+ <br>
+ <br>
+ In a workflow <span style="font-weight: bold;">with</span> native
+ calibration capability, the calibration curves would be used with
+ printarg during subsequent <span style="font-weight: bold;">profiling</span>
+ so that any ink limit calculations will reflect final device values,
+ while not otherwise using the calibration within the ICC workflow:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
+ href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
+ <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#I">-I
+ PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <br>
+ This will cause the .ti2 and resulting .ti3 and ICC profiles to
+ contain the calibration curves, allowing all the tools to be able to
+ compute final device value ink limits. The calibration curves must
+ also of course be installed into the printer. The means to do this
+ is currently outside the scope of Argyll (ie. either the print
+ system needs to be able to understand Argyll CAL format files, or
+ some tool will be needed to convert Argyll CAL files into the
+ printer calibration format).<br>
+ <br>
+ <br>
+ In a workflow <span style="font-weight: bold;">without</span>
+ native calibration capability, the calibration curves would be used
+ with printarg to <span style="text-decoration: underline;">apply</span>
+ the calibration to the test patch samples during subsequent <span
+ style="font-weight: bold;">profiling</span>, as well as embedding
+ it in the resulting .ti3 to allow all the tools to be able to
+ compute final device value ink limits:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
+ href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
+ <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#K">-K
+ PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <a href="cctiff.html#p4"></a><br>
+ To apply calibration to an ICC profile, so that a calibration
+ unaware CMM can be used:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="applycal.html">applycal</a> <a
+ href="applycal.html#p1">PrinterA.cal</a> <a
+ href="applycal.html#p2">PrinterA.icm</a> <a
+ href="applycal.html#p3">PrinterA_cal.icm</a><br>
+ <br>
+ To apply color management and calibration to a raster image:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">Source.icm</a> <a href="cctiff.html#p1">PrinterA.icm</a>
+ <a href="cctiff.html#p2">PrinterA_c.cal</a> <a
+ href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ <br>
+ or<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">Source.icm</a> <a href="cctiff.html#p1">PrinterA_c.icm</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ <br>
+ [ Note that cctiff will also process JPEG raster images. ]<br>
+ <br>
+ Another useful tool is <a href="synthcal.html">synthcal</a>, that
+ allows creating linear or synthetic calibration files for disabling
+ calibration or testing.<br>
+ Similarly, <a href="fakeread.html">fakeread</a> also supports
+ applying calibration curves and embedding them in the resulting .ti3
+ file<br>
+ <br>
+ If you want to create a pre-conditioning profile for use with <a
+ href="targen.html#c">targen -c</a>, then use the PrinterA.icm
+ profile, <b>NOT</b> PrinterA_c.icm that has calibration curves
+ applied.<br>
+ <h4><a name="PC6"></a>How profile ink limits are handled when
+ calibration is being used.</h4>
+ Even though the profiling process is carried out on top of the
+ linearized device, and the profiling is generally unaware of the
+ underlying non-linearized device values, an exception is made in the
+ calculation of ink limits during profiling. This is made possible by
+ including the calibration curves in the profile charts .ti2 and
+ subsequent .ti3 file and resulting ICC profile <span
+ style="font-weight: bold;">'targ'</span> text tag, by way of the <span
+ style="font-weight: bold;">printtarg</span> <span
+ style="font-weight: bold;">-I</span> or <span style="font-weight:
+ bold;">-K</span> options. This is done on the assumption that the
+ physical quantity of ink is what's important in setting the ink
+ limit, and that the underlying non-linearized device values
+ represent such a physical quantity.<br>
+ <br>
+ <br>
+ <hr size="2" width="100%">
+ <h3><a name="LP1"></a>Linking Profiles</h3>
+ Two device profiles can be linked together to create a device link
+ profile, than encapsulates a particular device to device transform.
+ Often this step is not necessary, as many systems and tools will
+ link two device profiles "on the fly", but creating a device link
+ profile gives you the option of using "smart CMM" techniques, such
+ as true gamut mapping, improved inverse transform accuracy, tailored
+ black generation and ink limiting.<br>
+ <br>
+ The overall process is to link the input space and output space
+ profiles using <a href="collink.html">collink</a>, creating a
+ device to device link profile. The device to device link profile can
+ then be used by cctiff (or other ICC device profile capable tools),
+ to color correct a raster files.<br>
+ <br>
+ Three examples will be given here, showing the three different modes
+ than <span style="font-weight: bold;">collink</span> supports.<br>
+ <br>
+ In <a href="collink.html#s">simple mode</a>, the two profiles are
+ linked together in a similar fashion to other <span
+ style="font-weight: bold;">CMMs</span> simply using the forward
+ and backwards color transforms defined by the profiles. Any gamut
+ mapping is determined by the content of the tables within the two
+ profiles, together with the particular intent chosen. Typically the
+ same intent will be used for both the source and destination
+ profile:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#s">-s</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#so">-op</a>
+ <a href="collink.html#p1">SouceProfile.icm</a> <a
+ href="collink.html#p2">DestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ <br>
+ In <a href="collink.html#g">gamut mapping mode</a>, the
+ pre-computed intent mappings inside the profiles are not used, but
+ instead the gamut mapping between source and destination is tailored
+ to the specific gamuts of the two profiles, and the intent parameter
+ supplied to <span style="font-weight: bold;">collink</span>.
+ Additionally, source and destination viewing conditions should be
+ provided, to allow the color appearance space conversion to work as
+ intended. The colorimetric B2A table in the destination profile is
+ used, and this will determine any black generation and ink limiting:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#g">-g</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">DestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ [ If your viewing environment for the display and print doesn't
+ match the ones implied by the <a href="colprof.html#c">-cmt</a> and
+ <a href="colprof.html#d">-dpp</a> options, leave them out, and
+ evaluate what, if any appearance transformation is appropriate for
+ your environment at a later stage. ]<br>
+ <br>
+ In <a href="collink.html#G">inverse output table gamut mapping mode</a>,
+ the pre-computed intent mappings inside the profiles are not used,
+ but instead the gamut mapping between source and destination is
+ tailored to the specific gamuts of the two profiles, and the intent
+ parameter supplied to <span style="font-weight: bold;">collink</span>.
+ In addition, the B2A table is <span style="font-weight: bold;">not</span>
+ used in the destination profile, but the A2B table is instead
+ inverted, leading to improved transform accuracy, and in CMYK
+ devices, allowing the ink limiting and black generation parameters
+ to be set:<br>
+ <br>
+ For a CLUT table based RGB printer destination profile, the
+ following would be appropriate:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">RGBDestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ For a CMYK profile, the total ink limit needs to be specified (a
+ typical value being 10% less than the value used in creating the
+ device test chart), and the type of black generation also needs to
+ be specified:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#l">-l250</a>
+ <a href="collink.html#k">-kr</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">CMYKDestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ Note that you should set the source (<a href="collink.html#c">-c</a>)
+ and destination (<a href="collink.html#d">-d</a>) viewing conditions
+ for the type of device the profile represents, and the conditions
+ under which it will be viewed.<br>
+ <br>
+ <h3><a name="LP3"></a>Image dependent gamut mapping using device
+ links<br>
+ </h3>
+ When images are stored in large gamut colorspaces (such as. L*a*b*,
+ ProPhoto, scRGB etc.), then using the colorspace gamut as the source
+ gamut for gamut mapping is generally a bad idea, as it leads to
+ overly compressed and dull images. The correct approach is to use a
+ source gamut that represents the gamut of the images themselves.
+ This can be created using tiffgamut, and an example workflow is as
+ follows:<br>
+ <br>
+ <a href="tiffgamut.html">tiffgamut</a> -f80 -pj -cmt ProPhoto.icm
+ image.tif<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qh</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#Gp">image.gam</a> <a href="collink.html#si">-ip</a>
+ <a href="collink.html#c">-cmt</a> <a href="collink.html#d">-dpp</a>
+ <a href="collink.html#p1">ProPhoto.icm</a> <a
+ href="collink.html#p2">RGBDestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
+ <a href="cctiff.html#p3">image.tif</a> <a href="cctiff.html#p4">printfile.tif</a><br>
+ <br>
+ The printfile.tif is then send to the printer without color
+ management, (i.e. in the same way the printer characterization test
+ chart was printed), since it is in the printers native colorspace.<br>
+ <br>
+ You can adjust how conservatively the image gamut is preserved using
+ the tiffgamut -f parameter. Omitting it or using a larger value (up
+ to 100) preserves the color gradations of even the lesser used
+ colors, at the cost of compressing the gamut more.<br>
+ Using a smaller value will preserve the saturation of the most
+ popular colors, at the cost of not preserving the color gradations
+ of less popular colors.<br>
+ <br>
+ You can create a gamut that covers a set of source images by
+ providing more than one image file name to tiffgamut. This may be
+ more efficient for a group of related images, and ensures that
+ colors are transformed in exactly the same way for all of the
+ images.<br>
+ <br>
+ An alternative generating a gamut for a specific set of images, is
+ to use a general smaller gamut definition (i.e. the sRGB profile),
+ or a gamut that represents the typical range of colors you wish to
+ preserve.<br>
+ <br>
+ The arguments to collink should be appropriate for the output device
+ type - see the collink examples in the above section.<br>
+ <h3><a name="LP2"></a>Soft Proofing Link</h3>
+ Often it is desirable to get an idea what a particular devices
+ output will look like using a different device. Typically this might
+ be trying to evaluate print output using a display. Often it is
+ sufficient to use an absolute or relative colorimetric transform
+ from the print device space to the display space, but while these
+ provide a colorimetric preview of the result, they do not take into
+ account the subjective appearance differences due to the different
+ device conditions. It can therefore be useful to create a soft proof
+ appearance transform using collink:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ila</a> <a href="collink.html#c">-cpp</a>
+ <a href="collink.html#d">-dmt</a> <a href="collink.html#l">-t250</a>&nbsp;<a
+ href="collink.html#k"></a><a href="collink.html#p1">CMYKDestinationProfile.icm</a>
+ <a href="collink.html#p2">MonitorProfile.icm</a> <a
+ href="collink.html#p3">SoftProof.icm</a><br>
+ <br>
+ We use the Luminance matched appearance intent, to preserve the
+ subjective apperance of the target device, which takes into account
+ the viewing conditions and assumes adaptation to the differences in
+ the luminence range, but otherwise not attempting to compress or
+ change the gamut.<br>
+ <br>
+ If your viewing environment for the display and print doesn't match
+ the ones implied by the <a href="collink.html#c">-cpp</a> and <a
+ href="collink.html#d">-dmt</a> options, then either leave them out
+ or substitute values that do match your environment.<br>
+ &nbsp;
+ <hr size="2" width="100%"><br>
+ <h3><a name="TR1"></a>Transforming colorspaces of raster files</h3>
+ Although a device profile or device link profile may be useful with
+ other programs and systems, Argyll provides the tool <a
+ href="cctiff.html">cctiff</a> for directly applying a device to
+ device transform to a <a href="File_Formats.html#TIFF">TIFF</a> or
+ <a href="File_Formats.html#JPEG">JPEG</a> raster file. The cctiff
+ tool is capable of linking an arbitrary sequence of device profiles,
+ device links, abstract profiles and calibration curves. Each device
+ profile can be preceded by the <span style="font-weight: bold;">-i</span>
+ option to indicate the intent that should be used. Both 8 and 16 bit
+ per component files can be handled, and up to 8 color channels. The
+ color transform is optimized to perform the overall transformation
+ rapidly.<br>
+ <br>
+ If a device link is to be used, the following is a typical example:<br>
+ <br>
+ <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <br>
+ <i><br>
+ </i>If a source and destination profile are to be used, the
+ following would be a typical example:<br>
+ <br>
+ <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
+ <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
+ href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
+ <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
+ href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <br>
+ <br>
+ <hr size="2" width="100%"><br>
+ <h3><a name="TV1"></a>Creating Video Calibration 3DLuts</h3>
+ Video calibration typically involves trying to make your actual
+ display device emulate an ideal video display, one which matches
+ what your Video media was intended to be displayed on. An ICC device
+ link embodies the machinery to do exactly this, to take device
+ values in the target source colorspace and transform them into an
+ actual output device colorspace. In the Video and Film industries a
+ very similar, but less sophisticated means of doing this is to use
+ 3DLuts, which come in a multitude of different format. ICC device
+ links have the advantage of being a superset of 3dLuts, encapsulated
+ in a standard file format.<br>
+ <br>
+ To facilitate Video calibration of certain Video systems, ArgyllCMS
+ supports some 3DLut output options as part of <a
+ href="collink.html">collink</a>.<br>
+ <br>
+ What follows here is an outline of how to create Video calibration
+ 3DLuts using ArgyllCMS. First comes a general discussion of various
+ aspects of video device links/3dLuts, and followed with some
+ specific advice regarding the systems that ArgyllCMS supports. Last
+ is some recommended scenarios for verifying the quality of Video
+ calibration achieved.<br>
+ <h5>1) How to display test patches.<br>
+ </h5>
+ Argyll's normal test patch display will be used by default, as long
+ as any video encoding range considerations are dealt with (see
+ Signal encoding below).<br>
+ <br>
+ An alternative when working with MadVR V 0.86.9 or latter, is to use
+ the madTPG to display the patches in which case the MadVR video
+ encoding range setting will operate. This can give some quality
+ benefits due to MadVR's use of dithering. To display patches using
MadVR rather than Argyll, start madTPG and then use the option "<b>-d
@@ -3213,52 +3295,55 @@ a
- madvr</b>" in dispcal, dispread and dispwin. Leave the MadTPG
- "VideoLUT" and "3dluts" buttons in their default&nbsp; (enabled)
- state, as the various tools will automatically take care of
- disabling the 3dLut and/or calibration curves as needed.<br>
- <br>
- Another option is to use a <a
- href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a>
- using the option "<b>-dcc</b>" in dispcal, dispread and dispwin.
- Note that the ChromeCast as a test patch source is probably the<b>
- least accurate</b> of your choices, since it up-samples the test
- patch and transforms from RGB to YCC and back, but should be
- accurate within ± 1 bit. You may have to modify any firewall to
- permit port 8081 to be accessed on your machine if it falls back to
- the Default receiver (see <a href="Installing.html">installation
- instructions</a> for your platform).
- <h5>2) White point calibration &amp; neutral axis calibration.</h5>
- A Device Link is capable of embodying all aspects of the
- calibration, including correcting the white point and neutral axis
- behavior of the output device, but making such a Link just from two
- ICC profile requires the use of Absolute Colorimetric intent during
- linking, and this reduces flexibility. In addition, a typical ICC
- device profile may not capture the neutral axis behavior quite as
- well as an explicit calibration, since it doesn't sample the
- displays neutral axis behaviour in quite as much detail. It is often
- desirable therefore, to calibrate the display device so as to have
- the specific white point desired so that one of the white point
- relative linking intents can be used, and to improve the displays
- general neutral axis behavior so that subsequent profiling works to
- best advantage. In summary, there are basically 4 options in
- handling white point &amp; neutral axis calibration:<br>
- <ul>
- <li>Don't bother correcting the white point. Most displays are
- close to the typical D65 target, and our eyes adapt to the white
- automatically unless it is very far from the daylight locus or
- we have something else to refer to. If this approach is taken,
- then display profiling and linking can ignore calibration, and
- one of the non Absolute Colorimetric intents (such as Relative
- Colorimetric) is chosen during profile linking. It is wise to
- make sure that the video card VideoLUTs are set to some known
- state (ie. linear using "dispwin -c" , or set by a an installed
- ICC display profile) though.<br>
- </li>
- <li>Calibrate the white point and linearise the neutral axis using
- the display controls. Many TV's have internal calibration
- controls that allow setting the white point, and possibly the
- neutral axis response. Either a dedicated Video calibration
+
+
+
+ madvr</b>" in dispcal, dispread and dispwin. Leave the MadTPG
+ "VideoLUT" and "3dluts" buttons in their default&nbsp; (enabled)
+ state, as the various tools will automatically take care of
+ disabling the 3dLut and/or calibration curves as needed.<br>
+ <br>
+ Another option is to use a <a
+ href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a>
+ using the option "<b>-dcc</b>" in dispcal, dispread and dispwin.
+ Note that the ChromeCast as a test patch source is probably the<b>
+ least accurate</b> of your choices, since it up-samples the test
+ patch and transforms from RGB to YCC and back, but should be
+ accurate within ± 1 bit. You may have to modify any firewall to
+ permit port 8081 to be accessed on your machine if it falls back to
+ the Default receiver (see <a href="Installing.html">installation
+ instructions</a> for your platform).
+ <h5>2) White point calibration &amp; neutral axis calibration.</h5>
+ A Device Link is capable of embodying all aspects of the
+ calibration, including correcting the white point and neutral axis
+ behavior of the output device, but making such a Link just from two
+ ICC profile requires the use of Absolute Colorimetric intent during
+ linking, and this reduces flexibility. In addition, a typical ICC
+ device profile may not capture the neutral axis behavior quite as
+ well as an explicit calibration, since it doesn't sample the
+ displays neutral axis behaviour in quite as much detail. It is often
+ desirable therefore, to calibrate the display device so as to have
+ the specific white point desired so that one of the white point
+ relative linking intents can be used, and to improve the displays
+ general neutral axis behavior so that subsequent profiling works to
+ best advantage. In summary, there are basically 4 options in
+ handling white point &amp; neutral axis calibration:<br>
+ <ul>
+ <li>Don't bother correcting the white point. Most displays are
+ close to the typical D65 target, and our eyes adapt to the white
+ automatically unless it is very far from the daylight locus or
+ we have something else to refer to. If this approach is taken,
+ then display profiling and linking can ignore calibration, and
+ one of the non Absolute Colorimetric intents (such as Relative
+ Colorimetric) is chosen during profile linking. It is wise to
+ make sure that the video card VideoLUTs are set to some known
+ state (ie. linear using "dispwin -c" , or set by a an installed
+ ICC display profile) though.<br>
+ </li>
+ <li>Calibrate the white point and linearise the neutral axis using
+ the display controls. Many TV's have internal calibration
+ controls that allow setting the white point, and possibly the
+ neutral axis response. Either a dedicated Video calibration
package could be used, or ArgyllCMS <a href="dispcal.html">dispcal</a>'s
@@ -3277,27 +3362,30 @@ a
- interactive adjustment mode can be used to set the white point.
- Note that while adjusting the neutral axis for neutrality may
- help, the Device Link will override the transfer curve
- characteristic of the calibrated display, so aiming for a
- transfer curve approximately the same as the target and
- reasonably perceptually linear is all that is required. If this
- approach is taken, then display profiling and linking can ignore
- calibration, and one of the non Absolute Colorimetric intents is
- chosen during profile linking. It is wise to make sure that the
- video card VideoLUTs are set to some known state&nbsp; though.</li>
- <li>[<b>Recommended</b>] Calibrate the white point and neutral
- axis using ArgyllCMS <a href="dispcal.html">dispcal</a>. Since
- the Device Link will override the calibrated transfer curve
- characteristic of the display, there there may be no point in
- doing much more than a medium calibration, and choosing a
- standard that has a straight segment from black, such as L*a*b*,
- sRGB, Rec709 or SMPTE240 curve. The exact shape of the
- calibration curve is not critically important, as the profiling
- and 3dLut will set the final response. If this approach is
- taken, then the resulting calibration file should be provided to
- dispread as the <a href="dispcal.html#k">-k parameter</a> or <a
+
+
+
+ interactive adjustment mode can be used to set the white point.
+ Note that while adjusting the neutral axis for neutrality may
+ help, the Device Link will override the transfer curve
+ characteristic of the calibrated display, so aiming for a
+ transfer curve approximately the same as the target and
+ reasonably perceptually linear is all that is required. If this
+ approach is taken, then display profiling and linking can ignore
+ calibration, and one of the non Absolute Colorimetric intents is
+ chosen during profile linking. It is wise to make sure that the
+ video card VideoLUTs are set to some known state&nbsp; though.</li>
+ <li>[<b>Recommended</b>] Calibrate the white point and neutral
+ axis using ArgyllCMS <a href="dispcal.html">dispcal</a>. Since
+ the Device Link will override the calibrated transfer curve
+ characteristic of the display, there there may be no point in
+ doing much more than a medium calibration, and choosing a
+ standard that has a straight segment from black, such as L*a*b*,
+ sRGB, Rec709 or SMPTE240 curve. The exact shape of the
+ calibration curve is not critically important, as the profiling
+ and 3dLut will set the final response. If this approach is
+ taken, then the resulting calibration file should be provided to
+ dispread as the <a href="dispcal.html#k">-k parameter</a> or <a
href="dispcal.html#K">-K parameter</a>.&nbsp; See also below <b>Choice
@@ -3313,475 +3401,477 @@ a
- of where to apply display per channel calibration curves.</b></li>
- <li>Choose one of the Absolute Colorimetric intents in collink
- (ie. -i aw). This greatly reduces flexibility, and may not be
- quite as accurate as an explicit calibration.</li>
- </ul>
- If an explicit calibration is used, then it is a good idea to add
- some test points down the neutral axis when profiling (targen <a
- href="targen.html#g">-g parameter</a>). <br>
- <br>
- <b>3) Choice of where to apply display per channel calibration
- curves</b><br>
- <br>
- If calibration curves are going to be used, then it needs to be
- decided where they will be applied in the video processing chain.
- There are two options:<br>
- <br>
- <b>a)</b> Install the calibration curves in the playback system. On
- a PC the display, this can be done by loading the calibration curves
- into the Video Card temporarily using "dispwin calibration.cal", or
- installing the ICC profile into the system persistently using
- something like "<a href="dispwin.html#I">dispwin -I profile.icm</a>",<br>
- or when using MadVR 0.86.9 or latter by creating a 3dLut with
- appended calibration curves using <a href="collink#H">-H
- display.cal</a>.<br>
- <br>
- <b>b)</b> The calibration can be incorporated into the Device
- Link/3dLUT by providing it to collink as the <a
- href="collink.html#a">-a display.cal</a>. This is the only option
- if the video display path does not have some separate facility to
- handle calibration curves. Note that if the playback system has
- graphic card VideoLUTs then they will have to be set to a defined
- consistent state such as linear. When using MadVR 0.86.9 or latter
- this will be done automatically since the -a option will append a
- linear set of calibration curves to the 3dLut.<br>
- <br>
- The choice is dictated by a number of considerations:<br>
- <ul>
- <li>Does the video playback path have a facility for installing
- the calibration curves ? If playing back system is a PC, then
- typically the Graphics Card supports 1D VideoLUTs, thereby
- making a) a possible choice.<br>
- </li>
- <li>Does the video playback <u>always</u> play back through the
- Video Card VideoLUTs ? Some systems do not apply VIdeoLUTs to
- things like overlay plane rendering. If not, then you need to
- choose b), but also make sure that if it does use the Video Card
- VideoLUTs in some situations, that they are set to linear (ie.
- dispcal -c). One way of determining when the VideoLUTs get used
- or not is to load a distinct calibration such as "strange.cal"
- provided in the <b>ref</b> folder, and check visually if it is
- affecting the video or not, ie. "dispcal strange.cal". Note that
- using MadVR 0.86.9 or latter in combination with a 3dLut with
- appended calibration curves will apply the calibration even with
- overlay plane rendering.<br>
- </li>
- <li>Do you want/need other applications to share the calibration
- curves or profile or not ? If you do, then it is desirable to
- choose a).</li>
- <li>Quality considerations. VideoLUTs may or may not be of greater
- depth than the standard 8 bit per color component frame buffer.
- If they are, and the video path passes that extra depth through
- to the display, and the display is capable of using that extra
- depth, then a) may be a desirable choice from a quality point of
- view. You can get some idea whether this is the case by running
- "dispcal -R". If the VideoLUT depth is not better than 8 bits,
- then it may be more desirable to choose b), since renders like
- MadVR can use dithering to give better than 8 bits precision in
- the video playback.<br>
- </li>
- </ul>
- <h5>4) Output device calibration and profiling.</h5>
- Output device profiling should basically follow the guide above in <a
- href="#PM1b">Adjusting and Calibrating a displays</a> and <a
- href="#PM1">Profiling Displays</a>. The assumption is that either
- you are calibrating/profiling your computer display for video, or
- your TV is connected to the computer you are creating
- calibrations/profiles on, and that the connection between the PC and
- TV display is such that full range RGB signals are being used, or
- that the Video card has automatically or manually been configured to
- scale full range RGB values to Video levels for the TV. If the
- latter is not possible, then use the -E options on dispcal and
- dispread. (See <b>Signal encoding</b> bellow for more details on
- this). It may also improve the accuracy of the display profile if
- you use the <a href="dispread.html#Z">dispread -Z</a> option to
- quantize the test values to the precision of the display
- system.&nbsp; Don't use the -E options on dispcal and dispread, nor
- the -Z option on dispread if you are using MadVR to display test
- patches using the "-d madvr" option.<br>
- <br>
- Once the profile has been created, it is possible to then use the
- resulting Device Link/3DLut with signal encoding other than full
- range or Video level RGB. <br>
- <h5>5) Target colorspace<br>
- </h5>
- In practical terms, there are five common Video and Digital Cinema
- encoding colorspaces. <br>
- <br>
- For Standard Definition:<br>
- <br>
- &nbsp;&nbsp;&nbsp; EBU 3213 or "PAL 576i" primaries.<br>
- <br>
- &nbsp;&nbsp;&nbsp; SMPTE RP 145 or "NTSC 480i" primaries.<br>
- <br>
- For High Definition:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Rec 709 primaries.<br>
- <br>
- For Ultra High Defintion<br>
- <br>
- &nbsp;&nbsp;&nbsp; Rec 2020 primaries.<br>
- <br>
- For Digital Cinema<br>
- <br>
- &nbsp;&nbsp;&nbsp; SMPTE-431-2&nbsp; or "DCI-P3"<br>
- <br>
- PAL and NTSC have historically had poorly specified transfer curve
- encodings, and the Rec 709 HDTV encoding curve is the modern <a
- href="http://www.poynton.com/notes/DVAI/DVAI_TOC_full.html#23">recommendation</a>,
- but the overall interpretation of Video sources may in fact be
- partly determined by the expected standard Video display device
- characteristics (see <b>Viewing conditions adjustment and gamut
- mapping</b> below for more details).<br>
- <br>
- To enable targeting these colorspaces, ArgyllCMS provides 5 ICC
- profiles in the ref directory to use as source
- colorspaces:&nbsp;&nbsp;&nbsp; <br>
- <br>
- &nbsp;&nbsp;&nbsp; EBU3213_PAL.icm<br>
- <br>
- &nbsp;&nbsp;&nbsp; SMPTE_RP145_NTSC.icm<br>
- <br>
- &nbsp;&nbsp;&nbsp; Rec709.icm<br>
- <br>
- &nbsp;&nbsp;&nbsp; Rec2020.icm<br>
- <br>
- &nbsp;&nbsp;&nbsp; SMPTE431_P3.icm<br>
- <h5>6) Signal encoding</h5>
- Typical PC display output uses full range RGB signals (0 .. 255 in 8
- bit parlance), while typical Video encoding allows some head &amp;
- footroom for overshoot and sync of digitized analog signals, and
- typically uses a 16..235 range in 8 bits. In many cases Video is
- encoded as luma and color difference signals YCbCr (loosely known as
- YUV as well), and this also uses a restricted range 16..235 for Y,
- and 16..240 for Cb and Cr in 8 bit encoding. The extended gamut
- xvYCC encoding uses 16..235 for Y, and 1..254 for Cb and Cr.<br>
- <br>
- The signal encoding comes into play in two situations: 1)
- Calibrating and profiling the display, and 2) Using the resulting
- Device Link/3DLut.<br>
- The encoding may need to be different in these two situations,
- either because different video source devices are being used for
- calibration/profiling and for video playback, or because the video
- playback system uses the Device Link/3DLut at a point in its
- processing pipeline that requires a specific encoding.<br>
- <br>
- For calibration &amp; profiling, the display will be driven by a
- computer system so that dispcal and dispread can be used. By default
- these programs expect to output full range RGB signals, and it is
- assumed that either the display accepts full range signals, or that
- the graphics card or connection path has been setup to convert the
- full range values into Video range signals automatically or
- manually. If this is not the case, then both dispcal and dispread
- have a -E option that will modify them to output Video range RGB
- values.<br>
- <br>
- If MadVR is the target of the calibration and profiling, then there
- is an option to use it to display the calibration and profiling test
- patches (<b>-d madvr</b>). In this case, MadVR should be configured
- appropriately for full range or Video range encoding, and the -E
- flag should <u>not</u> be used with dispcal or dispread, since
- MadVR will be taking care of such conversions.<br>
- <br>
- If a calibration file was created using dispcal -E, then using it in
- dispread will automatically trigger Video level RGB signals during
- profiling. Any time such a Video level calibration is loaded into
- the Graphics card VideoLUTs using dispwin, or the calibration curve
- is converted to a 'vcgt' tag in a profile, the curve will also
- convert full range RGB to Video range RGB. This should be kept in
- mind so that if video playback is being performed with the
- calibration curves installed in the Graphics card VideoLUTs, that
- full range is converted only once to Video range (ie. In this
- situation MadVR output should be set to full range if being played
- back through the calibration curves in hardware, but only if dispcal
- -E has been used). On the other hand, if the calibration curves are
- incorporated into the DeviceLink/3dLUT, then the conversion to Video
- levels has to be done somewhere else in the pipeline, such as using
- MadVR video level output, or by the graphics card, etc.<br>
- <br>
- When creating the Device Link/3dLut, it is often necessary to
- specify one of the video encodings so that it fits in to the
- processing pipeline correctly. For instance the eeColor needs to
- have input and output encoding that suits the HDMI signals passing
- through it, typically Video Range RGB. MadVR needs Video Level RGB
- to match the values being passed through the 3dLut at that point.<br>
- <br>
- There are several version of YCbCr encoding supported as well, even
- though neither the eeColor nor the current version of MadVR need or
- can use them at present.<br>
- <h5>7) Black point mapping</h5>
- <p>Video encoding assumes that the black displayed on a device is a
- perfect black (zero light). No real device has a perfect black,
- and if a colorimetric intent is used then certain image values
- near black will get clipped to the display black point, loosing
- shadow detail. To avoid this, some sort of black point mapping is
- usually desirable. There are two mechanisms available in collink:
- a) Custom EOTF with input and/or output black point mapping, or b)
- using one of the smart gamut mapping intents that does black point
- mapping (e.g. la, p, pa, ms or s).<br>
- </p>
- <h5>8) Viewing conditions adjustment and gamut mapping</h5>
- <p> </p>
- <p>In historical TV systems, there is a viewing conditions
- adjustment being made between the bright studio conditions that TV
- is filmed in, and the typical dim viewing environment that people
- view it in. This is created by the difference between the encoding
- response curve gamma of about 2.0, and a typical CRT response
- curve gamma of 2.4. <br>
- </p>
- <p>In theory Rec709 defines the video encoding, but it seems in
- practice that much video material is adjusted to look as intended
- when displayed on a reference monitor having a display gamma of
- somewhere between 2.2 and 2.4, viewed in a dim viewing
- environment. The modern standard covering the display EOTF
- (Electro-Optical Transfer Curve) is <a
- href="http://www.itu.int/rec/R-REC-BT.1886-0-201103-I">BT.1886</a>,
- which defines a pure power 2.4 curve with an input offset and
- scale applied to account for the black point offset while
- retaining dark shadow tonality. So another means of making the
- viewing adjustment is to use the BT.1886-like EOTF for Rec709
- encoded material. Collink supports this using the <a
- href="collink.html#I">-I b</a>, and allows some control over the
- degree of viewing conditions adjustment by overriding the BT.1886
- gamma&nbsp; using the <a href="collink.html#Ib">-I b:g.g</a>
- parameter. This is the <b>recommended</b> approach to start with,
- since it gives good results with a single parameter.<br>
- </p>
- <p>The addition of a second optional parameter <a
- href="collink.html#Ib">-I b:p.p:g.g</a>
- allows control over the degree of black point offset accounted for
- as an output offset, as opposed to input offset Once the effective
- gamma value has been chosen to suite the viewing conditions and
- set the overall contrast for mid greys, increasing the proportion
- of black offset accounted for in the output of the curve is a way
- of reducing the deep shadow detail, if it is being overly
- emphasized. </p>
- <p> An alternate approach to making this adjustment is to take
- advantage of the viewing conditions adjustment using the CIECAM02
- model available in collink. Some control over the degree of
- viewing conditions adjustment is possible by varying the viewing
- condition parameters. </p>
- <p>A third alternative is to combine the two approaches. The source
- is defined as Rec709 primaries with a BT.1886-like EOTF display in
- dim viewing conditions, and then CIECAM02 is used to adjust for
- the actual display viewing conditions. Once again, control over
- the degree of viewing conditions adjustment is possible by varying
- the viewing condition parameters<br>
- </p>
- <p><br>
- </p>
- <p><b>9) Correcting for any black point inaccuracy in the display
- profile</b><br>
- </p>
- <p>Some video display devices have particularly good black points,
- and any slight raising of the black due to innacuracies in the
- display profile near black can be objectionable. As well as using
- the <a href="targen.html#V">targen -V flag</a> to improve
- accuracy near black during profiling, if the display is known to
- be well behaved (ie. that it's darkest black is actually at RGB
- value 0,0,0), then the <a href="collink.html#b">collink -b</a>
- flag can be used, to force the source RGB 0,0,0 to map to the
- display 0,0,0.<br>
- </p>
- <h5>Putting it all together:</h5>
- In this example we choose to create a display calibration first
- using dispcal, and create a simple matrix profile as well:<br>
- <br>
- &nbsp; <tt>dispcal -v -o -qm -k0 -w 0.3127,0.3290 -gs -o TVmtx.icm
- TV</tt><br>
- <br>
- We are targeting a D65 white point (<tt>-w 0.3127,0.3290)</tt> and
- an sRGB response curve.<br>
- <br>
- If you are using the madTPG you would use:<br>
- <br>
- &nbsp; <tt>dispcal -v -d madvr -o -qm -k0 -w 0.3127,0.3290 -gs -o
- TVmtx.icm TV</tt><br>
- <br>
- Then we need to create a display patch test set. We can use the
- simple matrix to pre-condition the test patches, as this helps
- distribute them where they will be of most benefit. If have
- previously profiled your display, you should use that previous
- profile, or if you decided not to do a dispcal, then the Rec709.icm
- should be used as a substitute. Some per channel and a moderate
- number of full spread patches is used here - more will increase
- profiling accuracy, a smaller number will speed it up. Since the
- video or film material is typically viewed in a darkened viewing
- environment, and often uses a range of maximum brightnesses in
- different scenes, the device behavior in the dark regions of its
- response are often of great importance, and using the <a
- href="targen.html#V">targen -V</a> parameter can help improve the
- accuracy in this region at the expense of slightly lower accuracy in
- lighter regions.<br>
- <br>
- &nbsp; <tt>targen -v -d3 -s30 -g100 -f1000 -cTVmtx.icm -V1.8 TV</tt><br>
- <br>
- The display can then be measured:<br>
- <br>
- &nbsp; <tt>dispread -v -k -Z8 TV.cal TV</tt><br>
- <br>
- or using madTPG:<br>
- <br>
- &nbsp;dispread -v -d madvr -K TV.cal TV<br>
- <br>
- and then a cLUT type ICC profile created. Since we will be using
- collink smart linking, we minimize the B2A table size. We use the
- default colprof -V parameter carried through from targen:<br>
- <br>
- &nbsp; <tt>colprof -v -qh -bl TV</tt><br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the sample data and profile is behaving
- reasonably. Depending on the type of device, and the consistency of
- the readings, average errors of 5 or less, and maximum errors of 15
- or less would normally be expected. If errors are grossly higher
- than this, then this is an indication that something is seriously
- wrong with the device measurement, or profile creation.<br>
- <br>
- If you would like to use the display ICC profile for general color
- managed applications, then you would compute a more complete
- profile:<br>
- <br>
- &nbsp; <tt>colprof -v -qh TV</tt><br>
- <br>
- The recommended approach then is to create a Device Link that uses a
- BT.1886 black point and viewing conditions adjustment, say one of
- the following:<br>
- <br>
- <tt>&nbsp; collink -v -Ib:2.4 -b -G -ir Rec709.icm TV.icm
- HD.icm&nbsp;&nbsp; # dark conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib&nbsp;&nbsp;&nbsp;&nbsp; -b -G -ir
- Rec709.icm TV.icm HD.icm&nbsp;&nbsp; # dim conditions - good
- default</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib:2.1 -b -G -ir Rec709.icm TV.icm
- HD.icm&nbsp;&nbsp; # mid to dim conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib:2.0 -b -G -ir Rec709.icm TV.icm
- HD.icm&nbsp;&nbsp; # mid to light conditions</tt><br>
- <br>
- or you could do it using pure CIECAM02 adjustment and a black point
- mapping:<br>
- <br>
- <tt>&nbsp; collink -v -ctv -dmd -da:1 -G -ila Rec709.icm TV.icm
- HD.icm&nbsp; # very dark conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -ctv -dmd -da:3 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp; # dim conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -ctv -dmd -da:7 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp; # mid to dim conditions - good default</tt><tt><br>
- </tt><tt> &nbsp; collink -v -ctv -dmd -da:15 -G -ila Rec709.icm
- TV.icm HD.icm # mid conditions</tt><br>
- <br>
- or using both to model a reference video display system that is
- adapted to your viewing conditions:<br>
- <tt><br>
- </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:5&nbsp; -G -ila
- Rec709.icm TV.icm HD.icm # very dark conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:10 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp; # dim conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:18 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp; # mid to dark conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:30 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp;&nbsp; # mid to dark conditions</tt><br>
- <br>
- None of the above examples incorporate the calibration curves, so it
- is assumed that the calibration curves would be installed so that
- the Video Card applies calibration, ie:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <tt>dispwin TV.cal</tt><br>
- <br>
- or the simple matrix profile installed:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <tt>dispwin -I TVmtx.icm</tt><br>
- <br>
- or a the more complete display profile could be installed:<br>
- <br>
- &nbsp; dispwin -I TV.icm<br>
- <br>
- See also <a href="dispprofloc.html">here</a> for information on how
- to make sure the calibration is loaded on each system start. If not,
- then you will want to incorporate the calibration in the Device
- Link/3dlut by using collink "-a TV.cal".<br>
- <br>
- If the video path needs Video Level RGB encoding but does not
- provide a means to do this, then you will want to include the <b>-E</b>
- flag in the dispcal and dispread command lines above.<br>
- <br>
- Below are specific recommendation for the eeColor and MadVR that
- include the flags to create the .3dlut and encode the input and
- output values appropriately, but only illustrate using the
- recommended BT.1886 black point and viewing conditions adjustments,
- rather than illustrating CIECAM02 etc. use.<br>
- <br>
- For faster exploration of different collink option, you could omit
- the "colprof -bl" option, and use collink "-g" instead of "-G",
- since this<br>
- will greatly speed up collink. Once you are happy with the link
- details, you can then generate a higher quality link/3dLut using
- "collink -G ..".<br>
- <br>
- You can also increase the precision of the device profile by
- increasing the number of test patches measured (ie. up to a few
- thousand, depending on how long you are prepared to wait for the
- measurement to complete, and how stable your display and instrument
- are).<br>
- <br>
- Alternatives to relative colorimetric rendering ("-i r") or
- luminance matched appearance ("-i la") used in the examples above
- and below, are, perceptual ("-i p") which will ensure that the
- source gamut is compressed rather than clipped by the display, or
- even a saturation rendering ("-i ms"), which will expand the gamut
- of the source to the full range of the output.<br>
- <br>
- <br>
- <b>eeColor</b><br>
- <br>
- For PC use, where the encoding is full range RGB:<br>
- <br>
- &nbsp; <tt>collink -v -3e -Ib -b -G -ir -a TV.cal Rec709.icm TV.icm
- HD.icm </tt><br>
- <br>
- For correct operation both the 3DLut HD.txt and the per channel
- input curves HD-first1dred.txt, HD-first1dgreen.txt and
- HD-first1dblue.txt. the latter by copying them over the default
- input curve files uploaded by the TruVue application.<br>
- <br>
- See <a
- href="http://www.avsforum.com/t/1464890/eecolor-processor-argyllcms">&lt;http://www.avsforum.com/t/1464890/eecolor-processor-argyllcms&gt;</a>
- for some more details.<br>
- <br>
- Where the eeColor is connected from a Video source using HDMI, it
- will probably be processing TV RGB levels, or YCbCr encoded signals
- that it converts to/from RGB internally, so<br>
- <br>
- &nbsp; <tt>collink -v -3e -et -Et -Ib -b -G -ir -a TV.cal
- Rec709.icm TV.icm HD.icm </tt><br>
- <br>
- in this case just the HD.txt file needs installing on the eeColor,
- but make sure that the original linear "first1*.txt files are
- re-installed, or install the ones generated by collink, which will
- be linear for -e t mode.<br>
- <br>
- <b>MadVR</b><br>
- <br>
- MadVR 0.86.9 or latter has a number of features to support accurate
- profiling and calibration, and is the recommended version to
- use.&nbsp; It converts from the media colorspace to the 3dLut input
- space automatically with the type of source being played, but has
- configuration for to 5 3dLuts, each one optimized for a particular
- source color space. The advantage of building and installing several
- 3dLuts is that unnecessary gamut clipping can be avoided.<br>
- <br>
- If you are just building one 3dLut then Rec709 source is a good one
- to pick.<br>
- <br>
- If you want to share the VideoLUT calibration curves between your
- normal desktop and MadVR, then it is recommended that you install
- the display ICC profile and use the -H option:<br>
- <br>
- <tt>&nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir -H
- TV.cal Rec709.icm TV.icm HD.icm</tt><tt><br>
- </tt><tt> </tt><tt><br>
+
+
+
+ of where to apply display per channel calibration curves.</b></li>
+ <li>Choose one of the Absolute Colorimetric intents in collink
+ (ie. -i aw). This greatly reduces flexibility, and may not be
+ quite as accurate as an explicit calibration.</li>
+ </ul>
+ If an explicit calibration is used, then it is a good idea to add
+ some test points down the neutral axis when profiling (targen <a
+ href="targen.html#g">-g parameter</a>). <br>
+ <br>
+ <b>3) Choice of where to apply display per channel calibration
+ curves</b><br>
+ <br>
+ If calibration curves are going to be used, then it needs to be
+ decided where they will be applied in the video processing chain.
+ There are two options:<br>
+ <br>
+ <b>a)</b> Install the calibration curves in the playback system. On
+ a PC the display, this can be done by loading the calibration curves
+ into the Video Card temporarily using "dispwin calibration.cal", or
+ installing the ICC profile into the system persistently using
+ something like "<a href="dispwin.html#I">dispwin -I profile.icm</a>",<br>
+ or when using MadVR 0.86.9 or latter by creating a 3dLut with
+ appended calibration curves using <a href="collink#H">-H
+ display.cal</a>.<br>
+ <br>
+ <b>b)</b> The calibration can be incorporated into the Device
+ Link/3dLUT by providing it to collink as the <a
+ href="collink.html#a">-a display.cal</a>. This is the only option
+ if the video display path does not have some separate facility to
+ handle calibration curves. Note that if the playback system has
+ graphic card VideoLUTs then they will have to be set to a defined
+ consistent state such as linear. When using MadVR 0.86.9 or latter
+ this will be done automatically since the -a option will append a
+ linear set of calibration curves to the 3dLut.<br>
+ <br>
+ The choice is dictated by a number of considerations:<br>
+ <ul>
+ <li>Does the video playback path have a facility for installing
+ the calibration curves ? If playing back system is a PC, then
+ typically the Graphics Card supports 1D VideoLUTs, thereby
+ making a) a possible choice.<br>
+ </li>
+ <li>Does the video playback <u>always</u> play back through the
+ Video Card VideoLUTs ? Some systems do not apply VIdeoLUTs to
+ things like overlay plane rendering. If not, then you need to
+ choose b), but also make sure that if it does use the Video Card
+ VideoLUTs in some situations, that they are set to linear (ie.
+ dispcal -c). One way of determining when the VideoLUTs get used
+ or not is to load a distinct calibration such as "strange.cal"
+ provided in the <b>ref</b> folder, and check visually if it is
+ affecting the video or not, ie. "dispcal strange.cal". Note that
+ using MadVR 0.86.9 or latter in combination with a 3dLut with
+ appended calibration curves will apply the calibration even with
+ overlay plane rendering.<br>
+ </li>
+ <li>Do you want/need other applications to share the calibration
+ curves or profile or not ? If you do, then it is desirable to
+ choose a).</li>
+ <li>Quality considerations. VideoLUTs may or may not be of greater
+ depth than the standard 8 bit per color component frame buffer.
+ If they are, and the video path passes that extra depth through
+ to the display, and the display is capable of using that extra
+ depth, then a) may be a desirable choice from a quality point of
+ view. You can get some idea whether this is the case by running
+ "dispcal -R". If the VideoLUT depth is not better than 8 bits,
+ then it may be more desirable to choose b), since renders like
+ MadVR can use dithering to give better than 8 bits precision in
+ the video playback.<br>
+ </li>
+ </ul>
+ <h5>4) Output device calibration and profiling.</h5>
+ Output device profiling should basically follow the guide above in <a
+ href="#PM1b">Adjusting and Calibrating a displays</a> and <a
+ href="#PM1">Profiling Displays</a>. The assumption is that either
+ you are calibrating/profiling your computer display for video, or
+ your TV is connected to the computer you are creating
+ calibrations/profiles on, and that the connection between the PC and
+ TV display is such that full range RGB signals are being used, or
+ that the Video card has automatically or manually been configured to
+ scale full range RGB values to Video levels for the TV. If the
+ latter is not possible, then use the -E options on dispcal and
+ dispread. (See <b>Signal encoding</b> bellow for more details on
+ this). It may also improve the accuracy of the display profile if
+ you use the <a href="dispread.html#Z">dispread -Z</a> option to
+ quantize the test values to the precision of the display
+ system.&nbsp; Don't use the -E options on dispcal and dispread, nor
+ the -Z option on dispread if you are using MadVR to display test
+ patches using the "-d madvr" option.<br>
+ <br>
+ Once the profile has been created, it is possible to then use the
+ resulting Device Link/3DLut with signal encoding other than full
+ range or Video level RGB. <br>
+ <h5>5) Target colorspace<br>
+ </h5>
+ In practical terms, there are five common Video and Digital Cinema
+ encoding colorspaces. <br>
+ <br>
+ For Standard Definition:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; EBU 3213 or "PAL 576i" primaries.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; SMPTE RP 145 or "NTSC 480i" primaries.<br>
+ <br>
+ For High Definition:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rec 709 primaries.<br>
+ <br>
+ For Ultra High Defintion<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rec 2020 primaries.<br>
+ <br>
+ For Digital Cinema<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; SMPTE-431-2&nbsp; or "DCI-P3"<br>
+ <br>
+ PAL and NTSC have historically had poorly specified transfer curve
+ encodings, and the Rec 709 HDTV encoding curve is the modern <a
+ href="http://www.poynton.com/notes/DVAI/DVAI_TOC_full.html#23">recommendation</a>,
+ but the overall interpretation of Video sources may in fact be
+ partly determined by the expected standard Video display device
+ characteristics (see <b>Viewing conditions adjustment and gamut
+ mapping</b> below for more details).<br>
+ <br>
+ To enable targeting these colorspaces, ArgyllCMS provides 5 ICC
+ profiles in the ref directory to use as source
+ colorspaces:&nbsp;&nbsp;&nbsp; <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; EBU3213_PAL.icm<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; SMPTE_RP145_NTSC.icm<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rec709.icm<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rec2020.icm<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; SMPTE431_P3.icm<br>
+ <h5>6) Signal encoding</h5>
+ Typical PC display output uses full range RGB signals (0 .. 255 in 8
+ bit parlance), while typical Video encoding allows some head &amp;
+ footroom for overshoot and sync of digitized analog signals, and
+ typically uses a 16..235 range in 8 bits. In many cases Video is
+ encoded as luma and color difference signals YCbCr (loosely known as
+ YUV as well), and this also uses a restricted range 16..235 for Y,
+ and 16..240 for Cb and Cr in 8 bit encoding. The extended gamut
+ xvYCC encoding uses 16..235 for Y, and 1..254 for Cb and Cr.<br>
+ <br>
+ The signal encoding comes into play in two situations: 1)
+ Calibrating and profiling the display, and 2) Using the resulting
+ Device Link/3DLut.<br>
+ The encoding may need to be different in these two situations,
+ either because different video source devices are being used for
+ calibration/profiling and for video playback, or because the video
+ playback system uses the Device Link/3DLut at a point in its
+ processing pipeline that requires a specific encoding.<br>
+ <br>
+ For calibration &amp; profiling, the display will be driven by a
+ computer system so that dispcal and dispread can be used. By default
+ these programs expect to output full range RGB signals, and it is
+ assumed that either the display accepts full range signals, or that
+ the graphics card or connection path has been setup to convert the
+ full range values into Video range signals automatically or
+ manually. If this is not the case, then both dispcal and dispread
+ have a -E option that will modify them to output Video range RGB
+ values.<br>
+ <br>
+ If MadVR is the target of the calibration and profiling, then there
+ is an option to use it to display the calibration and profiling test
+ patches (<b>-d madvr</b>). In this case, MadVR should be configured
+ appropriately for full range or Video range encoding, and the -E
+ flag should <u>not</u> be used with dispcal or dispread, since
+ MadVR will be taking care of such conversions.<br>
+ <br>
+ If a calibration file was created using dispcal -E, then using it in
+ dispread will automatically trigger Video level RGB signals during
+ profiling. Any time such a Video level calibration is loaded into
+ the Graphics card VideoLUTs using dispwin, or the calibration curve
+ is converted to a 'vcgt' tag in a profile, the curve will also
+ convert full range RGB to Video range RGB. This should be kept in
+ mind so that if video playback is being performed with the
+ calibration curves installed in the Graphics card VideoLUTs, that
+ full range is converted only once to Video range (ie. In this
+ situation MadVR output should be set to full range if being played
+ back through the calibration curves in hardware, but only if dispcal
+ -E has been used). On the other hand, if the calibration curves are
+ incorporated into the DeviceLink/3dLUT, then the conversion to Video
+ levels has to be done somewhere else in the pipeline, such as using
+ MadVR video level output, or by the graphics card, etc.<br>
+ <br>
+ When creating the Device Link/3dLut, it is often necessary to
+ specify one of the video encodings so that it fits in to the
+ processing pipeline correctly. For instance the eeColor needs to
+ have input and output encoding that suits the HDMI signals passing
+ through it, typically Video Range RGB. MadVR needs Video Level RGB
+ to match the values being passed through the 3dLut at that point.<br>
+ <br>
+ There are several version of YCbCr encoding supported as well, even
+ though neither the eeColor nor the current version of MadVR need or
+ can use them at present.<br>
+ <h5>7) Black point mapping</h5>
+ <p>Video encoding assumes that the black displayed on a device is a
+ perfect black (zero light). No real device has a perfect black,
+ and if a colorimetric intent is used then certain image values
+ near black will get clipped to the display black point, loosing
+ shadow detail. To avoid this, some sort of black point mapping is
+ usually desirable. There are two mechanisms available in collink:
+ a) Custom EOTF with input and/or output black point mapping, or b)
+ using one of the smart gamut mapping intents that does black point
+ mapping (e.g. la, p, pa, ms or s).<br>
+ </p>
+ <h5>8) Viewing conditions adjustment and gamut mapping</h5>
+ <p> </p>
+ <p>In historical TV systems, there is a viewing conditions
+ adjustment being made between the bright studio conditions that TV
+ is filmed in, and the typical dim viewing environment that people
+ view it in. This is created by the difference between the encoding
+ response curve gamma of about 2.0, and a typical CRT response
+ curve gamma of 2.4. <br>
+ </p>
+ <p>In theory Rec709 defines the video encoding, but it seems in
+ practice that much video material is adjusted to look as intended
+ when displayed on a reference monitor having a display gamma of
+ somewhere between 2.2 and 2.4, viewed in a dim viewing
+ environment. The modern standard covering the display EOTF
+ (Electro-Optical Transfer Curve) is <a
+ href="http://www.itu.int/rec/R-REC-BT.1886-0-201103-I">BT.1886</a>,
+ which defines a pure power 2.4 curve with an input offset and
+ scale applied to account for the black point offset while
+ retaining dark shadow tonality. So another means of making the
+ viewing adjustment is to use the BT.1886-like EOTF for Rec709
+ encoded material. Collink supports this using the <a
+ href="collink.html#I">-I b</a>, and allows some control over the
+ degree of viewing conditions adjustment by overriding the BT.1886
+ gamma&nbsp; using the <a href="collink.html#Ib">-I b:g.g</a>
+ parameter. This is the <b>recommended</b> approach to start with,
+ since it gives good results with a single parameter.<br>
+ </p>
+ <p>The addition of a second optional parameter <a
+ href="collink.html#Ib">-I b:p.p:g.g</a> allows control over the
+ degree of black point offset accounted for as an output offset, as
+ opposed to input offset Once the effective gamma value has been
+ chosen to suite the viewing conditions and set the overall
+ contrast for mid greys, increasing the proportion of black offset
+ accounted for in the output of the curve is a way of reducing the
+ deep shadow detail, if it is being overly emphasized. </p>
+ <p> An alternate approach to making this adjustment is to take
+ advantage of the viewing conditions adjustment using the CIECAM02
+ model available in collink. Some control over the degree of
+ viewing conditions adjustment is possible by varying the viewing
+ condition parameters. </p>
+ <p>A third alternative is to combine the two approaches. The source
+ is defined as Rec709 primaries with a BT.1886-like EOTF display in
+ dim viewing conditions, and then CIECAM02 is used to adjust for
+ the actual display viewing conditions. Once again, control over
+ the degree of viewing conditions adjustment is possible by varying
+ the viewing condition parameters<br>
+ </p>
+ <p><br>
+ </p>
+ <p><b>9) Correcting for any black point inaccuracy in the display
+ profile</b><br>
+ </p>
+ <p>Some video display devices have particularly good black points,
+ and any slight raising of the black due to innacuracies in the
+ display profile near black can be objectionable. As well as using
+ the <a href="targen.html#V">targen -V flag</a> to improve
+ accuracy near black during profiling, if the display is known to
+ be well behaved (ie. that it's darkest black is actually at RGB
+ value 0,0,0), then the <a href="collink.html#b">collink -b</a>
+ flag can be used, to force the source RGB 0,0,0 to map to the
+ display 0,0,0.<br>
+ </p>
+ <h5>Putting it all together:</h5>
+ In this example we choose to create a display calibration first
+ using dispcal, and create a simple matrix profile as well:<br>
+ <br>
+ &nbsp; <tt>dispcal -v -o -qm -k0 -w 0.3127,0.3290 -gs -o TVmtx.icm
+ TV</tt><br>
+ <br>
+ We are targeting a D65 white point (<tt>-w 0.3127,0.3290)</tt> and
+ an sRGB response curve.<br>
+ <br>
+ If you are using the madTPG you would use:<br>
+ <br>
+ &nbsp; <tt>dispcal -v -d madvr -o -qm -k0 -w 0.3127,0.3290 -gs -o
+ TVmtx.icm TV</tt><br>
+ <br>
+ Then we need to create a display patch test set. We can use the
+ simple matrix to pre-condition the test patches, as this helps
+ distribute them where they will be of most benefit. If have
+ previously profiled your display, you should use that previous
+ profile, or if you decided not to do a dispcal, then the Rec709.icm
+ should be used as a substitute. Some per channel and a moderate
+ number of full spread patches is used here - more will increase
+ profiling accuracy, a smaller number will speed it up. Since the
+ video or film material is typically viewed in a darkened viewing
+ environment, and often uses a range of maximum brightnesses in
+ different scenes, the device behavior in the dark regions of its
+ response are often of great importance, and using the <a
+ href="targen.html#V">targen -V</a> parameter can help improve the
+ accuracy in this region at the expense of slightly lower accuracy in
+ lighter regions.<br>
+ <br>
+ &nbsp; <tt>targen -v -d3 -s30 -g100 -f1000 -cTVmtx.icm -V1.8 TV</tt><br>
+ <br>
+ The display can then be measured:<br>
+ <br>
+ &nbsp; <tt>dispread -v -k -Z8 TV.cal TV</tt><br>
+ <br>
+ or using madTPG:<br>
+ <br>
+ &nbsp;dispread -v -d madvr -K TV.cal TV<br>
+ <br>
+ and then a cLUT type ICC profile created. Since we will be using
+ collink smart linking, we minimize the B2A table size. We use the
+ default colprof -V parameter carried through from targen:<br>
+ <br>
+ &nbsp; <tt>colprof -v -qh -bl TV</tt><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the sample data and profile is behaving
+ reasonably. Depending on the type of device, and the consistency of
+ the readings, average errors of 5 or less, and maximum errors of 15
+ or less would normally be expected. If errors are grossly higher
+ than this, then this is an indication that something is seriously
+ wrong with the device measurement, or profile creation.<br>
+ <br>
+ If you would like to use the display ICC profile for general color
+ managed applications, then you would compute a more complete
+ profile:<br>
+ <br>
+ &nbsp; <tt>colprof -v -qh TV</tt><br>
+ <br>
+ The recommended approach then is to create a Device Link that uses a
+ BT.1886 black point and viewing conditions adjustment, say one of
+ the following:<br>
+ <br>
+ <tt>&nbsp; collink -v -Ib:2.4 -b -G -ir Rec709.icm TV.icm
+ HD.icm&nbsp;&nbsp; # dark conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib&nbsp;&nbsp;&nbsp;&nbsp; -b -G -ir
+ Rec709.icm TV.icm HD.icm&nbsp;&nbsp; # dim conditions - good
+ default</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib:2.1 -b -G -ir Rec709.icm TV.icm
+ HD.icm&nbsp;&nbsp; # mid to dim conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib:2.0 -b -G -ir Rec709.icm TV.icm
+ HD.icm&nbsp;&nbsp; # mid to light conditions</tt><br>
+ <br>
+ or you could do it using pure CIECAM02 adjustment and a black point
+ mapping:<br>
+ <br>
+ <tt>&nbsp; collink -v -ctv -dmd -da:1 -G -ila Rec709.icm TV.icm
+ HD.icm&nbsp; # very dark conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -ctv -dmd -da:3 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp; # dim conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -ctv -dmd -da:7 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp; # mid to dim conditions - good default</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -ctv -dmd -da:15 -G -ila Rec709.icm
+ TV.icm HD.icm # mid conditions</tt><br>
+ <br>
+ or using both to model a reference video display system that is
+ adapted to your viewing conditions:<br>
+ <tt><br>
+ </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:5&nbsp; -G -ila
+ Rec709.icm TV.icm HD.icm # very dark conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:10 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp; # dim conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:18 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp; # mid to dark conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:30 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp;&nbsp; # mid to dark conditions</tt><br>
+ <br>
+ None of the above examples incorporate the calibration curves, so it
+ is assumed that the calibration curves would be installed so that
+ the Video Card applies calibration, ie:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <tt>dispwin TV.cal</tt><br>
+ <br>
+ or the simple matrix profile installed:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <tt>dispwin -I TVmtx.icm</tt><br>
+ <br>
+ or a the more complete display profile could be installed:<br>
+ <br>
+ &nbsp; dispwin -I TV.icm<br>
+ <br>
+ See also <a href="dispprofloc.html">here</a> for information on how
+ to make sure the calibration is loaded on each system start. If not,
+ then you will want to incorporate the calibration in the Device
+ Link/3dlut by using collink "-a TV.cal".<br>
+ <br>
+ If the video path needs Video Level RGB encoding but does not
+ provide a means to do this, then you will want to include the <b>-E</b>
+ flag in the dispcal and dispread command lines above.<br>
+ <br>
+ Below are specific recommendation for the eeColor and MadVR that
+ include the flags to create the .3dlut and encode the input and
+ output values appropriately, but only illustrate using the
+ recommended BT.1886 black point and viewing conditions adjustments,
+ rather than illustrating CIECAM02 etc. use.<br>
+ <br>
+ For faster exploration of different collink option, you could omit
+ the "colprof -bl" option, and use collink "-g" instead of "-G",
+ since this<br>
+ will greatly speed up collink. Once you are happy with the link
+ details, you can then generate a higher quality link/3dLut using
+ "collink -G ..".<br>
+ <br>
+ You can also increase the precision of the device profile by
+ increasing the number of test patches measured (ie. up to a few
+ thousand, depending on how long you are prepared to wait for the
+ measurement to complete, and how stable your display and instrument
+ are).<br>
+ <br>
+ Alternatives to relative colorimetric rendering ("-i r") or
+ luminance matched appearance ("-i la") used in the examples above
+ and below, are, perceptual ("-i p") which will ensure that the
+ source gamut is compressed rather than clipped by the display, or
+ even a saturation rendering ("-i ms"), which will expand the gamut
+ of the source to the full range of the output.<br>
+ <br>
+ <br>
+ <b>eeColor</b><br>
+ <br>
+ For PC use, where the encoding is full range RGB:<br>
+ <br>
+ &nbsp; <tt>collink -v -3e -Ib -b -G -ir -a TV.cal Rec709.icm TV.icm
+ HD.icm </tt><br>
+ <br>
+ For correct operation both the 3DLut HD.txt and the per channel
+ input curves HD-first1dred.txt, HD-first1dgreen.txt and
+ HD-first1dblue.txt. the latter by copying them over the default
+ input curve files uploaded by the TruVue application.<br>
+ <br>
+ See <a
+ href="http://www.avsforum.com/t/1464890/eecolor-processor-argyllcms">&lt;http://www.avsforum.com/t/1464890/eecolor-processor-argyllcms&gt;</a>
+ for some more details.<br>
+ <br>
+ Where the eeColor is connected from a Video source using HDMI, it
+ will probably be processing TV RGB levels, or YCbCr encoded signals
+ that it converts to/from RGB internally, so<br>
+ <br>
+ &nbsp; <tt>collink -v -3e -et -Et -Ib -b -G -ir -a TV.cal
+ Rec709.icm TV.icm HD.icm </tt><br>
+ <br>
+ in this case just the HD.txt file needs installing on the eeColor,
+ but make sure that the original linear "first1*.txt files are
+ re-installed, or install the ones generated by collink, which will
+ be linear for -e t mode.<br>
+ <br>
+ <b>MadVR</b><br>
+ <br>
+ MadVR 0.86.9 or latter has a number of features to support accurate
+ profiling and calibration, and is the recommended version to
+ use.&nbsp; It converts from the media colorspace to the 3dLut input
+ space automatically with the type of source being played, but has
+ configuration for to 5 3dLuts, each one optimized for a particular
+ source color space. The advantage of building and installing several
+ 3dLuts is that unnecessary gamut clipping can be avoided.<br>
+ <br>
+ If you are just building one 3dLut then Rec709 source is a good one
+ to pick.<br>
+ <br>
+ If you want to share the VideoLUT calibration curves between your
+ normal desktop and MadVR, then it is recommended that you install
+ the display ICC profile and use the -H option:<br>
+ <br>
+ <tt>&nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir -H
+ TV.cal Rec709.icm TV.icm HD.icm</tt><tt><br>
+ </tt><tt> </tt><tt><br>
</tt><tt> &nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir </tt><tt><tt>-H
@@ -3808,8 +3898,11 @@ a
- TV.cal </tt>EBU3213_PAL.icm TV.icm SD_PAL.icm</tt><tt><br>
- </tt><tt> </tt><tt><br>
+
+
+
+ TV.cal </tt>EBU3213_PAL.icm TV.icm SD_PAL.icm</tt><tt><br>
+ </tt><tt> </tt><tt><br>
</tt><tt> &nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir </tt><tt><tt>-H
@@ -3836,15 +3929,18 @@ a
- TV.cal </tt>SMPTE_RP145_NTSC.icm TV.icm SD_NTSC.icm</tt><br>
- <br>
- For best quality it is better to let MadVR apply the calibration
- curves using dithering, and allow it to set the graphics card to
- linear by using the -a option:<br>
- <br>
- <tt>&nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir -a
- TV.cal Rec709.icm TV.icm HD.icm</tt><tt><br>
- </tt><tt> </tt><tt><br>
+
+
+
+ TV.cal </tt>SMPTE_RP145_NTSC.icm TV.icm SD_NTSC.icm</tt><br>
+ <br>
+ For best quality it is better to let MadVR apply the calibration
+ curves using dithering, and allow it to set the graphics card to
+ linear by using the -a option:<br>
+ <br>
+ <tt>&nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir -a
+ TV.cal Rec709.icm TV.icm HD.icm</tt><tt><br>
+ </tt><tt> </tt><tt><br>
</tt><tt> &nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir </tt><tt><tt>-a
@@ -3871,8 +3967,11 @@ a
- TV.cal </tt>EBU3213_PAL.icm TV.icm SD_PAL.icm</tt><tt><br>
- </tt><tt> </tt><tt><br>
+
+
+
+ TV.cal </tt>EBU3213_PAL.icm TV.icm SD_PAL.icm</tt><tt><br>
+ </tt><tt> </tt><tt><br>
</tt><tt> &nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir </tt><tt><tt>-a
@@ -3899,181 +3998,184 @@ a
- TV.cal </tt>SMPTE_RP145_NTSC.icm TV.icm SD_NTSC.icm</tt><br>
- <br>
- the consequence though is that the appearance of other application
- will shift when MadVR is using the 3dLut and loading the calibration
- curves.<br>
- <br>
- The 3dLut can be used by opening the MadVR settings dialog,
- selecting "calibration" and then selecting "calibrate this display
- by using an external 3DLUT file", and then using the file dialog to
- use it.<br>
- <br>
- If neither the -a no -H options are used, then no calibration curves
- will be appended to the 3dLut, and MadVR will not change the
- VideoLUTs when that 3dLut is in use. It is then up to you to manage
- the graphics card VideoLUTs in some other fashion.<tt><br>
- <br>
- </tt>
- <hr size="2" width="100%"><br>
- <h3><a name="TV2"></a>Verifying Video Calibration</h3>
- <p>Often it is desirable to verify the results of a video
- calibration and profile, and the following gives an outline of how
- to use ArgyllCMS tools to do this. It is only possible to expect
- perfect verification if a colorimetric intent was used during
- linking - currently it's not possible to exactly verify a
- perceptual or CIECAM02 viewing condition adjusted link.<br>
- <br>
- </p>
- <p>The first step is to create a set of test points. This is
- essentially the same as creating a set of test points for the
- purposes of profiling, although it is best not to create exactly
- the same set, so as to explore the colorspace at different
- locatioins. For the purposes here, we'll actually create a regular
- grid test set, since this makes it easier to visualize the
- results, although a less regular set would probably be better for
- numerical evaluation:<br>
- </p>
- <p>&nbsp; targen -v -d3 -e1 -m6 -f0 -W verify<br>
- </p>
- <p>We make sure there is at least one white patch usin g -e1, a 20%
- increment grid using -m6, no full spread patches, and create an
- X3DOM 3d visualization of the point set using the -W flag. It is
- good to take a look at the verifyd.x3d.html file using a Web
- browser. You may want to create several test sets that look at
- particular aspects, ie. neutral axis response, pure colorant
- responses, etc.<br>
- </p>
- <p>Next we create a reference file by simulating the expected
- response of the perfect video display system. Assuming the collink
- options were "-et -Et -Ib -G -ir Rec709.icm TV.icm HD.icm" then we
- would:<tt><tt><br>
- </tt></tt></p>
- <p><tt><tt>&nbsp; copy verify.ti1 ref.ti1<br>
- &nbsp; fakeread -v -b -Z8 TV.icm Rec709.icm ref<br>
- </tt></tt></p>
- <p>You should adjust the parameters as necessary, so that the
- reference matches the link options. For instance, if your link
- options included "-I b:0.2:2.15" then the equivalent fakeread
- option "-b 0.2:2.15:TV.icm" should be used, etc.<br>
- </p>
- <hr size="2" width="20%">
- <p>A sanity check we can make at this point is to see what the
- expected result of the profiling &amp; calibration will be, by
- simulating the reproduction of this test set:<br>
- </p>
- <p><tt>&nbsp; copy verify.ti1 checkA.ti1</tt><tt><br>
- &nbsp; fakeread -v -et -Z8 -p HD.icm -Et TV.icm checkA<br>
- </tt></p>
- <p>If you used collink -a, then the calibration incorporated in the
- device link needs to be undone to match what the display profile
- expects:</p>
- <p><tt>&nbsp; fakeread -v -et -Z8 -p HD.icm -Et -K TV.cal TV.icm
- checkA</tt></p>
- <p><tt>and then you can verify:<br>
- </tt></p>
- <p><tt>&nbsp; colverify -v -n -w -x ref.ti3 checkA.ti3<br>
- </tt></p>
- <p>If you have targeted some other white point rather than video D65
- for the display, then use the -N flag instead of -n to align the
- white points. [ Note that there can be some small discrepancies in
- this case in some parts of the color space if a CIECAM02 linking
- intent was used, due to the slightly different chromatic
- adaptation algorithm it uses compared to the one used by verify to
- match the white points.]<tt><br>
- </tt></p>
- <p><tt>&nbsp; v</tt><tt>erify -v -N -w -x ref.ti3 checkA.ti3</tt><br>
- </p>
- <p>This will give a numerical report of the delta E's, and also
- generate an X3DOM plot of the errors in L*a*b* space. The
- important thing is to take a look at the checkA.x3d.html file, to
- see if gamut clipping is occurring - this is the case if the large
- error vectors are on the sides or top of the gamut. Note that the
- perfect cube device space values become a rather distorted cube
- like shape in the perceptual L*a*b* space. If the vectors are
- small in the bulk of the space, then this indicates that the link
- is likely to be doing the right thing in making the display
- emulate the video colorspace with a BT.1886 like black point
- adjustment. You could also check just the in gamut test points
- using:<br>
- </p>
- <p><tt>&nbsp; v</tt><tt>erify -v -N -w -x -L TV.icm ref.ti3
- checkA.ti3<br>
- <br>
- </tt></p>
- <hr size="2" width="20%">
- <p>You can explicitly compare the gamuts of your video space and
- your display using the gamut tools:<br>
- </p>
- <p><tt>&nbsp; iccgamut -ff -ia Rec709</tt><tt><br>
- </tt><tt> &nbsp; iccgamut -ff -ia TV.icm</tt><tt><br>
- </tt><tt> &nbsp; viewgam -i Rec709.gam TV.gam gamuts</tt><br>
- </p>
- <p>and look at the gamuts.x3d.html file, as well as taking notice of
- % of the video volume that the display intersects. The X3DOM solid
- volume will be the video gamut, while the wire frame is the
- display gamut. If you are not targetting D65 with your display,
- you should use iccgamut <b>-ir</b> instead of <b>-ia</b>, so as
- to align the white points.<br>
- </p>
- <hr size="2" width="20%">
- <p>The main verification check is to actually measure the display
- response and compare it against the reference. Make sure the
- display is setup as you would for video playback and then use
- dispread:<br>
- </p>
- <p><tt>&nbsp; copy verify.ti1 checkB.ti1</tt><tt><br>
- </tt><tt> &nbsp; dispread -v -Z8 checkB</tt><br>
- </p>
- <p>You would add any other options needed (such as <b>-y</b> etc.)
- to set your instrument up properly. If you are using madTPG, then
- configure madVR to use the 3dLut you want to measure as the
- default, and also use the dispread -V flag to make sure that the
- 3dLut is being used for the measurements: [<b>Note</b> that if the
- version of MadVR you are using does not have radio buttons in its
- calibration setup to indicate a default 3dLut, then the 3dLut
- under test should be the only one set - all others should be
- blank. ]<br>
- </p>
- <p><tt>&nbsp; dispread -v -d madvr -V checkB</tt><br>
- </p>
- <p>Verify the same way as above:<br>
- </p>
- <p><tt>&nbsp; v</tt><tt>erify -v -n -w -x ref.ti3 checkB.ti3<br>
- </tt></p>
- <p>If your display does not cover the full gamut of your video
- source, the errors are probably dominated by out of gamut colors.
- You can verify just the in gamut test values by asking verify to
- skip them, and this will give a better notion of the actual device
- link and calibration accuracy:<tt><br>
- </tt></p>
- <p><tt>&nbsp; v</tt><tt>erify -v -n -w -x -L TV.icm ref.ti3
- checkB.ti3</tt></p>
- <p><br>
- </p>
- <p>&nbsp;<br>
- </p>
- <p><br>
- <br>
- </p>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+
+
+ TV.cal </tt>SMPTE_RP145_NTSC.icm TV.icm SD_NTSC.icm</tt><br>
+ <br>
+ the consequence though is that the appearance of other application
+ will shift when MadVR is using the 3dLut and loading the calibration
+ curves.<br>
+ <br>
+ The 3dLut can be used by opening the MadVR settings dialog,
+ selecting "calibration" and then selecting "calibrate this display
+ by using an external 3DLUT file", and then using the file dialog to
+ use it.<br>
+ <br>
+ If neither the -a no -H options are used, then no calibration curves
+ will be appended to the 3dLut, and MadVR will not change the
+ VideoLUTs when that 3dLut is in use. It is then up to you to manage
+ the graphics card VideoLUTs in some other fashion.<tt><br>
+ <br>
+ </tt>
+ <hr size="2" width="100%"><br>
+ <h3><a name="TV2"></a>Verifying Video Calibration</h3>
+ <p>Often it is desirable to verify the results of a video
+ calibration and profile, and the following gives an outline of how
+ to use ArgyllCMS tools to do this. It is only possible to expect
+ perfect verification if a colorimetric intent was used during
+ linking - currently it's not possible to exactly verify a
+ perceptual or CIECAM02 viewing condition adjusted link.<br>
+ <br>
+ </p>
+ <p>The first step is to create a set of test points. This is
+ essentially the same as creating a set of test points for the
+ purposes of profiling, although it is best not to create exactly
+ the same set, so as to explore the colorspace at different
+ locatioins. For the purposes here, we'll actually create a regular
+ grid test set, since this makes it easier to visualize the
+ results, although a less regular set would probably be better for
+ numerical evaluation:<br>
+ </p>
+ <p>&nbsp; targen -v -d3 -e1 -m6 -f0 -W verify<br>
+ </p>
+ <p>We make sure there is at least one white patch usin g -e1, a 20%
+ increment grid using -m6, no full spread patches, and create an
+ X3DOM 3d visualization of the point set using the -W flag. It is
+ good to take a look at the verifyd.x3d.html file using a Web
+ browser. You may want to create several test sets that look at
+ particular aspects, ie. neutral axis response, pure colorant
+ responses, etc.<br>
+ </p>
+ <p>Next we create a reference file by simulating the expected
+ response of the perfect video display system. Assuming the collink
+ options were "-et -Et -Ib -G -ir Rec709.icm TV.icm HD.icm" then we
+ would:<tt><tt><br>
+ </tt></tt></p>
+ <p><tt><tt>&nbsp; copy verify.ti1 ref.ti1<br>
+ &nbsp; fakeread -v -b -Z8 TV.icm Rec709.icm ref<br>
+ </tt></tt></p>
+ <p>You should adjust the parameters as necessary, so that the
+ reference matches the link options. For instance, if your link
+ options included "-I b:0.2:2.15" then the equivalent fakeread
+ option "-b 0.2:2.15:TV.icm" should be used, etc.<br>
+ </p>
+ <hr size="2" width="20%">
+ <p>A sanity check we can make at this point is to see what the
+ expected result of the profiling &amp; calibration will be, by
+ simulating the reproduction of this test set:<br>
+ </p>
+ <p><tt>&nbsp; copy verify.ti1 checkA.ti1</tt><tt><br>
+ &nbsp; fakeread -v -et -Z8 -p HD.icm -Et TV.icm checkA<br>
+ </tt></p>
+ <p>If you used collink -a, then the calibration incorporated in the
+ device link needs to be undone to match what the display profile
+ expects:</p>
+ <p><tt>&nbsp; fakeread -v -et -Z8 -p HD.icm -Et -K TV.cal TV.icm
+ checkA</tt></p>
+ <p><tt>and then you can verify:<br>
+ </tt></p>
+ <p><tt>&nbsp; colverify -v -n -w -x ref.ti3 checkA.ti3<br>
+ </tt></p>
+ <p>If you have targeted some other white point rather than video D65
+ for the display, then use the -N flag instead of -n to align the
+ white points. [ Note that there can be some small discrepancies in
+ this case in some parts of the color space if a CIECAM02 linking
+ intent was used, due to the slightly different chromatic
+ adaptation algorithm it uses compared to the one used by verify to
+ match the white points.]<tt><br>
+ </tt></p>
+ <p><tt>&nbsp; v</tt><tt>erify -v -N -w -x ref.ti3 checkA.ti3</tt><br>
+ </p>
+ <p>This will give a numerical report of the delta E's, and also
+ generate an X3DOM plot of the errors in L*a*b* space. The
+ important thing is to take a look at the checkA.x3d.html file, to
+ see if gamut clipping is occurring - this is the case if the large
+ error vectors are on the sides or top of the gamut. Note that the
+ perfect cube device space values become a rather distorted cube
+ like shape in the perceptual L*a*b* space. If the vectors are
+ small in the bulk of the space, then this indicates that the link
+ is likely to be doing the right thing in making the display
+ emulate the video colorspace with a BT.1886 like black point
+ adjustment. You could also check just the in gamut test points
+ using:<br>
+ </p>
+ <p><tt>&nbsp; v</tt><tt>erify -v -N -w -x -L TV.icm ref.ti3
+ checkA.ti3<br>
+ <br>
+ </tt></p>
+ <hr size="2" width="20%">
+ <p>You can explicitly compare the gamuts of your video space and
+ your display using the gamut tools:<br>
+ </p>
+ <p><tt>&nbsp; iccgamut -ff -ia Rec709</tt><tt><br>
+ </tt><tt> &nbsp; iccgamut -ff -ia TV.icm</tt><tt><br>
+ </tt><tt> &nbsp; viewgam -i Rec709.gam TV.gam gamuts</tt><br>
+ </p>
+ <p>and look at the gamuts.x3d.html file, as well as taking notice of
+ % of the video volume that the display intersects. The X3DOM solid
+ volume will be the video gamut, while the wire frame is the
+ display gamut. If you are not targetting D65 with your display,
+ you should use iccgamut <b>-ir</b> instead of <b>-ia</b>, so as
+ to align the white points.<br>
+ </p>
+ <hr size="2" width="20%">
+ <p>The main verification check is to actually measure the display
+ response and compare it against the reference. Make sure the
+ display is setup as you would for video playback and then use
+ dispread:<br>
+ </p>
+ <p><tt>&nbsp; copy verify.ti1 checkB.ti1</tt><tt><br>
+ </tt><tt> &nbsp; dispread -v -Z8 checkB</tt><br>
+ </p>
+ <p>You would add any other options needed (such as <b>-y</b> etc.)
+ to set your instrument up properly. If you are using madTPG, then
+ configure madVR to use the 3dLut you want to measure as the
+ default, and also use the dispread -V flag to make sure that the
+ 3dLut is being used for the measurements: [<b>Note</b> that if the
+ version of MadVR you are using does not have radio buttons in its
+ calibration setup to indicate a default 3dLut, then the 3dLut
+ under test should be the only one set - all others should be
+ blank. ]<br>
+ </p>
+ <p><tt>&nbsp; dispread -v -d madvr -V checkB</tt><br>
+ </p>
+ <p>Verify the same way as above:<br>
+ </p>
+ <p><tt>&nbsp; v</tt><tt>erify -v -n -w -x ref.ti3 checkB.ti3<br>
+ </tt></p>
+ <p>If your display does not cover the full gamut of your video
+ source, the errors are probably dominated by out of gamut colors.
+ You can verify just the in gamut test values by asking verify to
+ skip them, and this will give a better notion of the actual device
+ link and calibration accuracy:<tt><br>
+ </tt></p>
+ <p><tt>&nbsp; v</tt><tt>erify -v -n -w -x -L TV.icm ref.ti3
+ checkB.ti3</tt></p>
+ <p><br>
+ </p>
+ <p>&nbsp;<br>
+ </p>
+ <p><br>
+ <br>
+ </p>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/XRGA.html b/doc/XRGA.html
new file mode 100644
index 0000000..295d7b2
--- /dev/null
+++ b/doc/XRGA.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=windows-1252">
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll XRGA conversion</title>
+ </head>
+ <body>
+ <br>
+ <h2> <u>Conversion to/from XRGA<br>
+ </u></h2>
+ After purchasing Gretag-Macbeth, X-Rite harmonized the subtly
+ different calibration standards the two companies were using for
+ their reflective measurement instruments, in order to minimize
+ changes with the introduction of new instruments. The result was the
+ <a href="http://www.xrite.com/xrite-graphic-arts-standard">XRGA
+ standard</a>, introduced in September 2010.<br>
+ <br>
+ Current X-Rite instruments are natively calibrated to XRGA, while
+ older instruments from X-Rite are calibrated to XRDI, and
+ Gretag-Macbeth instruments to GMDI standards. To smooth the
+ interchange of old and new instruments, a spectral <a
+href="https://www.xrite.com/documents/literature/en/L7-462_XRGA_WhitePaper_en.pdf">conversion
+
+
+ is possible</a> between these different standards. While such a
+ conversion is not perfect, it reduces the discontinuities between
+ old instrument families and current X-Rite instruments.<br>
+ <br>
+ By default, Argyll will use the native calibration of Gretag-Macbeth
+ and X-Rite instruments. These are summarized here:<br>
+ <br>
+ &nbsp; <br>
+ <table border="0" cellpadding="2" cellspacing="2">
+ <tbody>
+ <tr>
+ <td valign="top"><a href="instruments.html#DTP20">DTP20
+ "Pulse"</a>&nbsp; <br>
+ </td>
+ <td valign="top">XRDI<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top"><a href="instruments.html#DTP22">DTP22
+ Digital Swatchbook</a></td>
+ <td valign="top">XRDI<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top"><a href="instruments.html#DTP41">DTP41</a></td>
+ <td valign="top">XRDI<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top"><a href="instruments.html#dtp51">DTP51</a></td>
+ <td valign="top">XRDI<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top"> <a href="instruments.html#sl">Spectrolino</a>/
+ <a href="instruments.html#ss">SpectroScan</a></td>
+ <td valign="top">GMDI<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top"><a href="instruments.html#i1p">Eye-One Pro</a>
+ Rev A-D</td>
+ <td valign="top">GMDI<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top"><a href="instruments.html#ColorMunki"><span
+ style="text-decoration: underline;">ColorMunki</span></a>
+ Design or Photo</td>
+ <td valign="top">XRGA<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top"><a href="instruments.html#i1p2">Eye-One Pro2</a>
+ (Eye-One Pro Rev E)</td>
+ <td valign="top">XRGA<br>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br>
+ <br>
+ You can override this and force reflective data to be a particular
+ calibration standard in two ways:<br>
+ <br>
+ <a name="A"></a>Using the <b>-A</b> command line option in <a
+ href="spotread.html#A">spotread</a> and <a
+ href="chartread.html#A">chartread</a>:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <b>-A </b>N|A|X|G<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>N</b> argument sets
+ the calibration to Native.<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>A</b> argument sets
+ the calibration to XRGA.<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>X</b> argument sets
+ the calibration to XRDI.<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>G</b> argument sets
+ the calibration to GMDI.<br>
+ <br>
+ <br>
+ Or by setting an environment variable:<br>
+ (Note that command line options will override this.)<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"><a name="ARGYLL_XRGA"></a>ARGYLL_XRGA</span><br>
+ <br>
+ <div style="margin-left: 40px;"> If the <span style="font-weight:
+ bold;">ARGYLL_XRGA&nbsp;</span> environment variable is set to:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <b>XRGA</b>, then all Getag-MacBeth/X-Rite
+ reflective measurements will be converted to XRGA.<br>
+ <b>&nbsp;&nbsp;&nbsp; XRDI</b>, then all Getag-MacBeth/X-Rite
+ reflective measurements will be converted to XRDI.<br>
+ <b>&nbsp;&nbsp;&nbsp; GMDI</b>, then all Getag-MacBeth/X-Rite
+ reflective measurements will be converted to GMDI.<br>
+ <br>
+ If not set (or set to some other string), then the native
+ calibration will be used. Note that the values must be upper case.<br>
+ </div>
+ <span style="font-weight: bold;"></span><br>
+ All of the above except the <b>DTP51</b> can have a conversion
+ applied. <br>
+ (The DTP51 returns only colorimetric data, while the conversion
+ requires spectral data.)<br>
+ <br>
+ </body>
+</html>
diff --git a/doc/afiles b/doc/afiles
index a73a8ba..d820c7f 100644
--- a/doc/afiles
+++ b/doc/afiles
@@ -3,6 +3,7 @@ DocLicense.txt
License.txt
License2.txt
License3.txt
+License4.txt
ArgyllDoc.html
ChangesSummary.html
ColorManagement.html
@@ -48,6 +49,7 @@ i1p.jpg
sl.jpg
ss.jpg
JETI_1211.jpg
+JETI_1501.jpg
ColorHug.jpg
EX1.jpg
SMCube.jpg
@@ -135,6 +137,7 @@ viewgam.html
xicclu.html
oeminst.html
ucmm.html
+XRGA.html
Q60.jpg
DC.jpg
SG.jpg
@@ -144,6 +147,7 @@ i1scan14.jpg
HCT.jpg
CMP_DT_003.jpg
CMP_Digital_Target-4.jpg
+CMP_Digital_Target-7.jpg
colorchecker.jpg
SpyderChecker.jpg
SpyderChecker24.jpg
diff --git a/doc/average.html b/doc/average.html
index 231df92..e67ab2d 100644
--- a/doc/average.html
+++ b/doc/average.html
@@ -10,8 +10,7 @@
<h2><b>spectro/average</b></h2>
<h3>Summary</h3>
Average or merge two or more <a href="File_Formats.html#.ti3">.ti3</a>
- measurement
- files.<br>
+ measurement files.<br>
If only one input file is provided, all the patches with the same
device values will be average together.<br>
<h3>Usage</h3>
@@ -19,35 +18,78 @@
<span style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;"></span></small><span
style="font-family: monospace;">usage: average [-options]
- input1.ti3
- input2.ti3 ... output.ti3</span><br style="font-family:
+ input1.ti3 input2.ti3 ... output.ti3</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Verbose</span><br style="font-family: monospace;">
+
+
+
+ Verbose</span><br>
+ <span style="font-family: monospace;">&nbsp;-e
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Median rather than average</span><br>
+ <tt>&nbsp;-g&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Geometric Median of PCS in encoded space</tt><tt><br>
+ </tt><tt>&nbsp;-L&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Geometric Median of PCS in L*a*b* space</tt><tt><br>
+ </tt><tt>&nbsp;-X&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Geometric Median of PCS in XYZ space</tt><br>
<span style="font-family: monospace;">&nbsp;-m&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Merge
+
+
+
rather than average</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;input1.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
First
+
+
+
input file</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;input2.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Second
+
+
+
input file</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;...&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
etc.</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;output.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Resulting
+
+
+
averaged or merged output file</span><br>
<br>
<br>
All keywords and other table data will be taken from the first input
file. By default the input files are averaged, but they can be
- merged
- by using the <span style="font-weight: bold;">-m</span> flag.<br>
+ merged by using the <span style="font-weight: bold;">-m</span>
+ flag.<br>
<br>
The fields must be the same and in the same order. For averaging,
- the
- device values must be the same and in the same order.<br>
+ the device values must be the same and in the same order.<br>
+ <br>
+ If the <b>-e</b> option is used, then the independent median (i.e.
+ Marginal median) of the field values is used, rather than the
+ average. <br>
+ <br>
+ If the<b> </b><b>-g</b> option is used, then <a
+ href="https://en.wikipedia.org/wiki/Geometric_median">Geometric
+ Median</a> of PCS values is computed in their encoded space (i.e.
+ XYZ or L*a*b*).<br>
+ <br>
+ If the <b>-L</b> option is used, then Geometric Median of PCS
+ values is computed in L*a*b* space.<br>
+ <br>
+ If the <b>-X</b> option is used, then Geometric Median of PCS
+ values is computed in XYZ space.<br>
<br>
</body>
</html>
diff --git a/doc/chartread.html b/doc/chartread.html
index e9dddaf..19f4add 100644
--- a/doc/chartread.html
+++ b/doc/chartread.html
@@ -28,6 +28,8 @@ Verbose
+
+
mode</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#c">-c listno</a><span
@@ -44,6 +46,8 @@ transmission
+
+
measurement mode<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#d">-d</a><span
@@ -56,6 +60,8 @@ measurement
+
+
mode (white Y relative results)</span></small><small><span
style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;"><br>
@@ -66,6 +72,8 @@ measurement
+
+
Display type - instrument specific list to choose from.</span></font><br>
<small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#e">-e</a><span
@@ -77,6 +85,8 @@ measurement
+
+
mode (absolute results)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#p">-p</a><span
@@ -89,12 +99,16 @@ by
+
+
patch rather than strip</span></small><br>
<small><span style="font-family: monospace;"></span>&nbsp; <a
style="font-family: monospace;" href="#x">-x [lx]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Take
+
+
manually entered values, either L*a*b* (-xl) or XYZ (-xx).</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -107,6 +121,8 @@ Don't
+
+
save spectral information (default saves spectral)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#l">-l</a><span
@@ -126,6 +142,8 @@ partly
+
+
read chart<br>
&nbsp;<a href="#I">-I</a>
file.cal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Override
@@ -136,6 +154,8 @@ partly
+
+
Set filter configuration:<br>
&nbsp;
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -143,6 +163,8 @@ partly
+
+
None<br>
&nbsp;
p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -150,6 +172,8 @@ partly
+
+
Polarising filter<br>
&nbsp;
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -157,6 +181,8 @@ partly
+
+
D65<br>
&nbsp;
u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -164,8 +190,14 @@ partly
+
+
U.V. Cut</span></font><small><span style="font-family:
monospace;"></span><span style="font-family: monospace;"></span></small><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#A">-A N|A|X|G</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ XRGA conversion</span></font> (default N)<br>
<font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#N">-N</a><span
style="font-family: monospace;">
@@ -190,6 +222,8 @@ partly
+
+
Apply Colorimeter Correction Matrix</span></font><br>
<span style="font-family: monospace;">&nbsp;<a href="#X2">-X
file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -203,6 +237,8 @@ Samples
+
+
for calibration</span><br>
<small><span style="font-family: monospace;">&nbsp;</span><a style="
font-family: monospace;" href="#Q">-Q observ</a><span
@@ -216,6 +252,8 @@ Samples
+
+
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span></small><small><span
style="font-family: monospace;">1931_2 </span></small><small><span
style="font-family: monospace;"> (def.)</span></small><small><span
@@ -232,6 +270,8 @@ patch
+
+
consistency tolerance by ratio (if available)<br>
</span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#S">-S</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -242,6 +282,8 @@ strip
+
+
&amp; unexpected value warnings</span></font><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -250,6 +292,8 @@ Override
+
+
serial port flow control: n = none, h = HW, x = Xon/Xoff</span></font><br
style="font-family: monospace;">
<small><span style="font-family: monospace;"></span><small
@@ -263,6 +307,8 @@ Override
+
+
&nbsp;Base name for input[</span><a style="font-family:
monospace;" href="File_Formats.html#.ti2">.ti2</a><span
style="font-family: monospace;">]/output[</span><a
@@ -410,6 +456,8 @@ Override
+
+
-I</span> parameter allows overriding the .ti2 calibration curves
placed in the resulting .ti3 file with the actual calibration that
was used for that particular print.<br>
@@ -421,6 +469,21 @@ Override
simulation, or Ultra Violet Cut filter, and this option allows the
instrument to be configured appropriately.<br>
<br>
+ <a name="A"></a>The <b>-A</b> options allows overriding the default
+ or environment variable set <a href="XRGA.html">XRGA</a>
+ conversion:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <b>-A N|A|X|G</b><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>N</b> argument sets
+ the calibration to Native (default).<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>A</b> argument sets
+ the calibration to XRGA.<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>X</b> argument sets
+ the calibration to XRDI.<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>G</b> argument sets
+ the calibration to GMDI.<br>
+ <br>
<a name="N"></a> <span style="font-weight: bold;">-N</span> Any
instrument that requires regular calibration will ask for
calibration on initial start-up. Sometimes this can be awkward if
diff --git a/doc/colprof.html b/doc/colprof.html
index 755226b..d5df56e 100644
--- a/doc/colprof.html
+++ b/doc/colprof.html
@@ -9,9 +9,11 @@
<body>
<h2> profile/colprof</h2>
<h3>Summary</h3>
- Create an&nbsp;<a href="File_Formats.html#ICC">ICC</a> profile from
- the&nbsp;<a href="File_Formats.html#.ti3">.ti3</a> test chart patch
- values.<br>
+ Create an RGB, CMY or CMYK <a href="File_Formats.html#ICC">ICC</a>
+ profile from the&nbsp;<a href="File_Formats.html#.ti3">.ti3</a> test
+ chart patch values.<br>
+ [ Note that currently, Monochrome and N-Color profiles are not
+ supported. ]<br>
<h3>Usage Summary</h3>
&nbsp;<tt><small>colprof [-<i>options</i>] inoutfile<br>
&nbsp;<a href="#v">-v</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -48,6 +50,10 @@
+
+
+
+
&nbsp; &nbsp; &nbsp; &nbsp; Verbose mode<br>
&nbsp;<a href="#A">-A "manufacturer"</a>&nbsp; Set the
manufacturer description string<br>
@@ -86,6 +92,10 @@
+
+
+
+
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Default
intent: Perceptual, Rel. Colorimetric, Saturation, Abs.
Colorimetric</small></tt><tt><br>
@@ -129,6 +139,10 @@
+
+
+
+
&nbsp; &nbsp; &nbsp; &nbsp; Don't create input (Device) shaper
curves<br>
</small></tt><tt><small>&nbsp;<a href="#np">-np</a>
@@ -168,6 +182,10 @@
+
+
+
+
&nbsp; &nbsp; &nbsp; &nbsp; Don't create output (PCS) shaper
curves<br>
</small></tt><tt><small>&nbsp;<a href="#nc">-nc</a>
@@ -221,6 +239,10 @@ x
+
+
+
+
max K, r = ramp K<br>
&nbsp;<a href="#kp">-k p stle stpo enpo enle shape</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -267,6 +289,10 @@ White
+
+
+
+
- 1.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -313,6 +339,10 @@ Wh
+
+
+
+
0.0 - Bk 1.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -359,6 +389,10 @@ Wh
+
+
+
+
0.0 - Bk 1.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -404,6 +438,10 @@ Black
+
+
+
+
0.0 - 1.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -450,6 +488,10 @@ concave,
+
+
+
+
1.0-2.0 convex<br>
&nbsp;<a href="#K">-K parameters</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -476,6 +518,10 @@ concave,
+
+
+
+
Same as -k, but target is K locus rather than K value itself<br>
&nbsp;<a href="#l">-l <i>tlimit</i></a>&nbsp;&nbsp; &nbsp;
&nbsp; &nbsp;&nbsp; override CMYK total ink limit, 0 - 400%
@@ -529,6 +575,10 @@ cLUT
+
+
+
+
x = XYZ cLUT, X = display XYZ cLUT + matrix<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -574,6 +624,10 @@ s
+
+
+
+
shaper+matrix, m = matrix only,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -620,6 +674,10 @@ S
+
+
+
+
single shaper+matrix<br>
&nbsp;<a href="#u">-u</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -651,6 +709,10 @@ S
+
+
+
+
If input profile, auto scale WP to allow extrapolation</small></tt><tt><br>
</tt><tt> </tt><tt><small><small>&nbsp;<a href="#uc">-uc</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
@@ -699,6 +761,10 @@ and
+
+
+
+
primaries to be +ve</tt><tt><br>
&nbsp;<a href="#B">-B X,Y,Z</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -709,6 +775,10 @@ and
+
+
+
+
Display Black Point override hack<br>
&nbsp;<a href="#V">-V demphasis</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -725,6 +795,10 @@ and
+
+
+
+
Degree of dark region cLUT grid emphasis 1.0-3.0 (default 1.00 =
none)<br>
</tt><tt>&nbsp;</tt><tt><small><small><a href="#f">-f [<i>illum</i>]</a>
@@ -754,6 +828,10 @@ and
+
+
+
+
M0, M1, M2, </small></small></tt><tt><small><small><small>A,
C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp ]</small></small></small></tt><tt><br>
</tt><tt><small><small><small><small>&nbsp;<a href="#i">-i <i>illum</i></a>&nbsp;&nbsp;
@@ -780,6 +858,10 @@ and
+
+
+
+
&nbsp; &nbsp; &nbsp; &nbsp; Choose illuminant for
computation of CIE XYZ from spectral data &amp; FWA:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -816,6 +898,10 @@ D50M2,
+
+
+
+
D65, F5, F8, F10 or file.sp</small></small></small><br>
&nbsp;<a href="#o">-o <i>observ</i></a>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; Choose CIE Observer for spectral data:<br>
@@ -853,82 +939,22 @@ D50M2,
+
+
+
+
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </small></tt><tt><small>(def.)</small></tt><tt><small>,
1964_10, S&amp;B 1955_2, shaw, J&amp;V 1978_2<br>
&nbsp;<a href="#r">-r avgdev</a> &nbsp; &nbsp; &nbsp;
&nbsp;&nbsp; Average deviation of device+instrument readings as
a percentage (default 0.5%)<br>
- &nbsp;<a href="#s">-s src.icc</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Apply
-gamut
-mapping
-to
-output
-profile
-perceptual
-B2A
-table
-for
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- given source<br>
- &nbsp;<a href="#S">-S src.icc</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ &nbsp;<a href="#s">-s src.icm|cperc</a> &nbsp; Apply gamut
+ mapping to output profile perceptual B2A table for given source,
+ or compression percentage<br>
+ &nbsp;<a href="#S">-S src.icm|experc</a>&nbsp; Apply gamut
+ mapping to output profile perceptual and saturation B2A table,
+ or expansion percentage<br>
+ &nbsp;<a href="#nP">-nP</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -937,9 +963,6 @@ for
- Apply gamut mapping to output profile perceptual and saturation
- B2A table<br>
- &nbsp;<a href="#nP">-nP</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -969,13 +992,13 @@ for
+ Use colormetric source gamut to make output profile perceptual
+ table<br>
+ &nbsp;<a href="#nS">-nS</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Use colormetric source gamut to make output profile perceptual
- table<br>
- &nbsp;<a href="#nS">-nS</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1053,6 +1076,10 @@ for
+
+
+
+
Override gamut mapping intent for output profile saturation
table:<br>
</small></tt><tt><small> &nbsp; &nbsp; &nbsp;
@@ -1105,9 +1132,17 @@ for
+
+
+
+
pa - Perceptual Appearance</small></tt><br>
<tt><tt><small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
lp - Luminance Preserving Perceptual</small></tt><br>
</tt><tt> </tt><tt><small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1143,6 +1178,10 @@ for
+
+
+
+
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ms - Saturation<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; s - Enhanced Saturation [ICC
@@ -1171,6 +1210,10 @@ for
+
+
+
+
rl - White Point Matched Colorimetric (Lab)<br>
&nbsp;<a href="#c">-c viewcond</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1206,6 +1249,10 @@ for
+
+
+
+
set input viewing conditions for output profile CIECAM02 gamut
mapping,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1242,6 +1289,10 @@ for
+
+
+
+
either an enumerated choice, or a parameter<br>
&nbsp;<a href="#d">-d viewcond</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1277,6 +1328,10 @@ for
+
+
+
+
set output viewing conditions for output profile CIECAM02, gamut
mapping<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1313,6 +1368,10 @@ for
+
+
+
+
either an enumerated choice, or a parameter:value change<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1348,6 +1407,10 @@ for
+
+
+
+
Also sets out of gamut clipping CAM space.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1383,6 +1446,10 @@ for
+
+
+
+
Enumerated Viewing Conditions:<br>
</small></tt><tt><small>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp;&nbsp; &nbsp; pp - Practical Reflection Print (ISO-3664
@@ -1447,6 +1514,10 @@ for
+
+
+
+
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp; c = transparency (default average)<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
@@ -1495,6 +1566,10 @@ for
+
+
+
+
g:glare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare light % of
ambient (default 5)</span><br style="font-family:
monospace;">
@@ -1544,6 +1619,10 @@ for
+
+
+
+
Create gamut gammap_p.x3d.html and gammap_s.x3d.html diagostics<br>
</small></tt><tt><small>&nbsp;<a href="#O">-O outputfile</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
@@ -1580,6 +1659,10 @@ Override
+
+
+
+
the default output filename &amp; extension.</small></tt><tt><br>
</tt><tt> </tt><tt><small>&nbsp;<a href="#p1"><i>inoutfile</i></a>
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Base name for
@@ -1650,7 +1733,8 @@ Override
Perceptual, <span style="font-weight: bold;">r</span> to set
Relative Colorimetric, <span style="font-weight: bold;">s</span> to
set Saturation, and <span style="font-weight: bold;">a</span> to
- set Absolute colorimetric.<br>
+ set Absolute colorimetric. Some CMM's will use this to determine the
+ default intent that they will use.<br>
<br>
<a name="q"></a> The <b>-q</b> parameter sets the level of effort
and/or detail in the resulting profile. For table based profiles
@@ -1736,6 +1820,10 @@ the
+
+
+
+
device and CIE/spectral sample data and calibration curves used to
create a profile is stored in the <span style="font-weight: bold;">'targ'</span>
text tag in the resulting ICC profile. To suppress this and make the
@@ -1772,6 +1860,10 @@ the
+
+
+
+
</span>flag. <span style="font-weight: bold;">Note</span> that this
will then preclude final calibrated device value ink limits from
being computed for the resulting profile in subsequent use (ie. <a
@@ -1843,6 +1935,10 @@ the
+
+
+
+
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
&nbsp;_______&nbsp; enle<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1879,6 +1975,10 @@ the
+
+
+
+
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1914,6 +2014,10 @@ the
+
+
+
+
|&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1949,6 +2053,10 @@ the
+
+
+
+
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1984,6 +2092,10 @@ the
+
+
+
+
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; /<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
stle&nbsp; | ------/<br>
@@ -2027,6 +2139,10 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
+
+
+
+
Black<br>
</tt> <br>
For minimum sensitivity of printed output to the lighting spectrum,
@@ -2286,6 +2402,10 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
+
+
+
+
Violet</span> spectral content, otherwise FWA compensation won't
work properly. This means you ideally need to measure your
illuminant spectrum using an instrument that can measure down to
@@ -2428,31 +2548,54 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
<br>
<a name="S"></a><a name="s"></a><span style="font-weight: bold;">-s
-S&nbsp; </span>In order to generate perceptual and saturation
- intent B2A tables for output profiles, it is necessary to specify at
- least one profile to define what source gamut should be used in the
- source to destination gamut mapping. [For more information on <span
+ intent B2A tables for output profiles, it is necessary to have
+ something that defines what source gamut should be used to create
+ the source to destination gamut mapping. [For more information on <span
style="text-decoration: underline;">why</span> a source gamut is
needed, see <a href="iccgamutmapping.html">About ICC profiles and
- Gamut Mapping</a>] The <b>-S</b> parameter is used to do this,
- and doing so causes perceptual and saturation tables to be
+ Gamut Mapping</a>].&nbsp; The <b>-S</b> parameter is used to do
+ this, and doing so causes perceptual and saturation tables to be
generated. If only a perceptual intent is needed, then the <b>-s</b>
flag can be used, and the saturation intent will use the same table
- as the perceptual intent. Note that a input, output, display or
- device colororspace profile should be specified, not a non-device
- colorspace, device link, abstract or named color profile.<br>
- If no source gamut is specified for a cLUT Display profile, then an
- ICC Version 2.2.0 profile will be created with only an A2B0 and B2A0
- tag. If a source gamut is specified, then an ICC Version 2.4.0
- profile will be created with a full complement of B2A tags to
- support all intents. The source gamut is created from the
- corresponding intent table of the provided profile to the output
- table being created. A TIFF or JPEG file containing an embedded ICC
- profile may be supplied as the argument.<br>
+ as the perceptual intent.<br>
+ <br>
+ There are two ways of specifying a source gamut 1) Specify a
+ specific source ICC profile or 2) Specify a general compression of
+ the output gamut as a percentage. With the second choice, incoming
+ colors that are up to the percentage outside the devices gamut will
+ be compressed to fit into it. The same percentage is used for
+ expansion if a saturation table is generated, or a separate
+ percentage can be specified by including both a <b>-s</b> and <b>-S</b>
+ percentage. You can optionally specify <u>both</u> and input ICC
+ profile and a general compression percentage by using the -S option
+ twice, in which case the input profile determines just the luminance
+ range mapping, with the percentage determining the gamut volume
+ compression. If a percentage compression is specified without an ICC
+ profile, then the incoming luminance range will be assumed to be
+ full range (perfect white to perfect black), which is compatible
+ with idealized colorspaces such as sRGB, AdobeRGB and other working
+ RGB spaces. The input viewing conditions are applicable to the
+ assumed full range input.<br>
+ <br>
+ If no source ICC or compression percentage is specified for a cLUT
+ Display profile, then an ICC Version 2.2.0 profile will be created
+ with only an A2B0 and B2A0 tag. If a source gamut is specified, then
+ an ICC Version 2.4.0 profile will be created with a full complement
+ of B2A tags to support all intents.<br>
+ <br>
+ The source gamut is created from the corresponding intent table of
+ the provided profile to the output table being created. A TIFF or
+ JPEG file containing an embedded ICC profile may be supplied as the
+ argument, instead of an ICC profile.<br>
+ <br>
<span style="font-weight: bold;">Note</span> that input profiles and
matrix profiles will only contain a colorimetric intent table or
matrix, and hence the <span style="font-weight: bold;">-s</span>
and <span style="font-weight: bold;">-S</span> option is not
relevant.<br>
+ <b>Note</b> that an input, output, display or device colororspace
+ profile should be specified, not a non-device colorspace, device
+ link, abstract or named color profile.<br>
<br>
<a name="nP"></a><span style="font-weight: bold;">-nP</span>:
Normally when a source profile is provided to define the source
@@ -2499,7 +2642,9 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
space should be Jab appearance space, with the viewing conditions
generally being those of the input profile viewing conditions. The
input profile will normally be the one used to create a source image
- gamut using <span style="font-weight: bold;">tiffgamut</span>.<br>
+ gamut using <span style="font-weight: bold;">tiffgamut</span>. Note
+ that a source gamut is not used if a general compression ratio gamut
+ mapping is used.<br>
<br>
<b><a name="p"></a></b>The <b>-p</b> option allows specifying one
or more abstract profiles that will be applied to the output tables,
diff --git a/doc/dispcal.html b/doc/dispcal.html
index d66caf5..ff96ff2 100644
--- a/doc/dispcal.html
+++ b/doc/dispcal.html
@@ -1,28 +1,28 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>dispcal</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- </head>
- <body>
- <h2><b>spectro/dispcal</b></h2>
- <h3>Summary</h3>
- Given calibration target information [white point, maximum
- brightness, and response curve ("gamma")], display a series of test
- patches on the display, and using the colorimetric values read,
- create a calibration lookup tables that make the display meet the
- desired target. The type of instrument is determined by the
- communication port selected. Emission and display measurement
- instruments are supported.<br>
- <h3>Usage</h3>
- <font size="-1"><span style="font-family: monospace;">dispcal
- [-options]</span><i style="font-family: monospace;"> inoutfile</i><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#v">-v [n]</a><span
- style="font-family: monospace;">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispcal</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispcal</b></h2>
+ <h3>Summary</h3>
+ Given calibration target information [white point, maximum
+ brightness, and response curve ("gamma")], display a series of test
+ patches on the display, and using the colorimetric values read,
+ create a calibration lookup tables that make the display meet the
+ desired target. The type of instrument is determined by the
+ communication port selected. Emission and display measurement
+ instruments are supported.<br>
+ <h3>Usage</h3>
+ <font size="-1"><span style="font-family: monospace;">dispcal
+ [-options]</span><i style="font-family: monospace;"> inoutfile</i><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v [n]</a><span
+ style="font-family: monospace;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -70,18 +70,18 @@
-
- Verbose mode<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#display">-display displayname</a><span
- style="font-family: monospace;"> [X11 only] Choose X11 display
- name<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- [X11 only]Choose the display from the following list (default
- 1),<br>
+
+ Verbose mode<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [X11 only] Choose X11 display
+ name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [X11 only]Choose the display from the following list (default
+ 1),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
and
optionally
@@ -137,9 +137,9 @@ for
-
- VideoLUT access.</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ VideoLUT access.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Choose
the
@@ -195,8 +195,8 @@ list
-
- 1)</span></font><br>
+
+ 1)</span></font><br>
<span style="font-family: monospace;">&nbsp;<a href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -243,9 +243,9 @@ list
-
- Display via a web server at port (default 8080)</span><br>
- <span style="font-family: monospace;">&nbsp;<a href="#dmadvr">-dmadvr</a>
+
+ Display via a web server at port (default 8080)</span><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#dmadvr">-dmadvr</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -276,8 +276,8 @@ list
-
- [MSWin] Display via MadVR Video Renderer</span><br>
+
+ [MSWin] Display via MadVR Video Renderer</span><br>
<tt>&nbsp;</tt><tt><a href="#dcc">-dcc[:n]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -288,13 +288,13 @@ list
-
- </tt><tt>Display via n'th ChromeCast (default 1, ? for list)</tt><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span><span style="font-family:
- monospace;"></span>&nbsp; <span style="font-family: monospace;"></span></font><small
- style="font-family: monospace;"><span style="font-family:
+
+ </tt><tt>Display via n'th ChromeCast (default 1, ? for list)</tt><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span>&nbsp; <span style="font-family: monospace;"></span></font><small
+ style="font-family: monospace;"><span style="font-family:
monospace;"></span><a style="font-family: monospace;" href="#c">-c
@@ -342,37 +342,37 @@ list
-
- listno</a><span style="font-family: monospace;"> &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set communication port from
- the following list (default 1)<br>
- </span></small><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#r">-r</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Report on the calibrated display then
- exit</span></font><font size="-1"><span style="font-family:
- monospace;"></span><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span><span style="font-family:
- monospace;"><br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#R">-R</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Report on the uncalibrated display then
- exit</span></font><font size="-1"><span style="font-family:
- monospace;"></span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#m">-m</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; </span></font><font size="-1"><span
- style="font-family: monospace;">Skip</span><span
- style="font-family: monospace;"> adjustment of the monitor
- controls</span></font><br>
- &nbsp; <font size="-1"><span style="font-family: monospace;"><a
- href="#o">-o [profile.icm]</a>&nbsp;&nbsp;&nbsp;&nbsp; Create
- fast matrix/shaper profile [different filename to outfile.icm]<br>
+
+ listno</a><span style="font-family: monospace;"> &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set communication port from
+ the following list (default 1)<br>
+ </span></small><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#r">-r</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Report on the calibrated display then
+ exit</span></font><font size="-1"><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#R">-R</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Report on the uncalibrated display then
+ exit</span></font><font size="-1"><span style="font-family:
+ monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#m">-m</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; </span></font><font size="-1"><span
+ style="font-family: monospace;">Skip</span><span
+ style="font-family: monospace;"> adjustment of the monitor
+ controls</span></font><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#o">-o [profile.icm]</a>&nbsp;&nbsp;&nbsp;&nbsp; Create
+ fast matrix/shaper profile [different filename to outfile.icm]<br>
&nbsp;<a href="#O">-O description</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -420,8 +420,8 @@ list
-
- Fast ICC Profile Description string (Default "outfile")<br>
+
+ Fast ICC Profile Description string (Default "outfile")<br>
&nbsp;<a href="#u">-u</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Update
previous
@@ -477,12 +477,12 @@ ICC
-
- profile VideoLUTs</span><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span><br style="font-family:
- monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#q">-q [lmh]</a><span
+
+ profile VideoLUTs</span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#q">-q [lmh]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -530,8 +530,8 @@ ICC
-
- Quality - Low, Medium (def), High<br>
+
+ Quality - Low, Medium (def), High<br>
&nbsp;<a href="#p">-p</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -568,10 +568,10 @@ ICC
-
- Use telephoto mode (ie. for a projector) (if available)<br>
- &nbsp;</span></font><font size="-1"><span style="font-family:
- monospace;"><a href="#y">-y X</a>
+
+ Use telephoto mode (ie. for a projector) (if available)<br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><a href="#y">-y X</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -619,12 +619,12 @@ ICC
-
- Display type - instrument specific list to choose from.</span></font><font
- size="-1"><span style="font-family: monospace;"><br
- style="font-family: monospace;">
- </span><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#t">-t [temp]</a><span
+
+ Display type - instrument specific list to choose from.</span></font><font
+ size="-1"><span style="font-family: monospace;"><br
+ style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#t">-t [temp]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
White
Daylight
@@ -680,10 +680,10 @@ in
-
- deg. K (deflt.)<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
+
+ deg. K (deflt.)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
href="#T">-T [temp]</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
White
Black
@@ -739,11 +739,11 @@ temperaturee
-
- in deg. K</span></font><br style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#w">-w x,y</a><span
+
+ in deg. K</span></font><br style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#w">-w x,y</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -791,11 +791,11 @@ temperaturee
-
- Set the target white point as chromaticity coordinates</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#b">-b bright</a><span
+
+ Set the target white point as chromaticity coordinates</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#b">-b bright</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -843,11 +843,11 @@ temperaturee
-
- Set the target white brightness in cd/m^2</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#g">-g gamma</a><span
+
+ Set the target white brightness in cd/m^2</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#g">-g gamma</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -895,9 +895,9 @@ temperaturee
-
- Set the target response curve gamma (Def. 2.4)</span><br
- style="font-family: monospace;">
+
+ Set the target response curve gamma (Def. 2.4)</span><br
+ style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -945,9 +945,9 @@ temperaturee
-
- Use "-gl" for L*a*b* curve</span><br style="font-family:
- monospace;">
+
+ Use "-gl" for L*a*b* curve</span><br style="font-family:
+ monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -995,8 +995,8 @@ temperaturee
-
- &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Use "-gs" for sRGB curve<br>
+
+ &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Use "-gs" for sRGB curve<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Use
"-g709"
@@ -1052,8 +1052,8 @@ use
-
- -a as well!)<br>
+
+ -a as well!)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1101,9 +1101,9 @@ use
-
- Use "-g240" for SMPTE 240M curve </span></font><font size="-1"><span
- style="font-family: monospace;">(should use -a as well!)</span></font><br>
+
+ Use "-g240" for SMPTE 240M curve </span></font><font size="-1"><span
+ style="font-family: monospace;">(should use -a as well!)</span></font><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1151,7 +1151,7 @@ use
-
+
Use "-G2.4 -f0" for BT.1886</span></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1192,13 +1192,13 @@ use
-
- <br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#G">-G gamma</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Set the target response curve actual technical gamma<br>
+
+ <br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#G">-G gamma</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Set the target response curve actual technical gamma<br>
&nbsp;<a href="#f">-f [degree]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Amount
of
@@ -1254,8 +1254,8 @@ output
-
- offset (default all output offset)<br>
+
+ offset (default all output offset)<br>
&nbsp;<a href="#a">-a ambient</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1303,17 +1303,17 @@ output
-
- Use viewing condition adjustment for ambient in Lux<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#k">-k factor</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Amount to try and correct black point hue. Default 1.0, LCD
- default 0.0<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#A">-A rate</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Rate of blending from neutral to black point. Default 4.0<br>
+
+ Use viewing condition adjustment for ambient in Lux<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#k">-k factor</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Amount to try and correct black point hue. Default 1.0, LCD
+ default 0.0<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#A">-A rate</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Rate of blending from neutral to black point. Default 4.0<br>
&nbsp;<a href="#bhack">-b</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1322,10 +1322,10 @@ output
-
- Use forced black point hack<br>
- </span></font> <font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
+
+ Use forced black point hack<br>
+ </span></font> <font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
href="#B">-B bkbright</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1373,12 +1373,12 @@ output
-
- Set the target black brightness in cd/m^2</span></font><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#e">-e [n]</a><span
+
+ Set the target black brightness in cd/m^2</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#e">-e [n]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1426,12 +1426,12 @@ output
-
- Run n verify passes on final curves<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#z">-<font size="-1">z</font></a><span style="font-family:
- monospace;">
+
+ Run n verify passes on final curves<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#z">-<font size="-1">z</font></a><span style="font-family:
+ monospace;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1479,13 +1479,13 @@ output
-
- Run only verify pass on installed calibration curves</span></font><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;<a href="#P">-P
- ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
- and scale it</span><br style="font-family: monospace;">
+
+ Run only verify pass on installed calibration curves</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;<a href="#P">-P
+ ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
+ and scale it</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ho,vi:
0.0
@@ -1541,8 +1541,8 @@ center,
-
- = right/bottom etc.</span><br style="font-family: monospace;">
+
+ = right/bottom etc.</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ss:
0.5
@@ -1598,9 +1598,9 @@ normal,
-
- = double etc.<br>
- </span></font><font size="-1"><span style="font-family:
+
+ = double etc.<br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1635,10 +1635,10 @@ normal,
-
- ss,vs: = optional horizontal, vertical scale.</span></font><br>
- <font size="-1"><span style="font-family: monospace;"> &nbsp;<a
- href="#F">-F</a>
+
+ ss,vs: = optional horizontal, vertical scale.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;"> &nbsp;<a
+ href="#F">-F</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1686,11 +1686,11 @@ normal,
-
- Fill whole screen with black background</span></font><font
- size="-1"><span style="font-family: monospace;"></span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
- size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
+
+ Fill whole screen with black background</span></font><font
+ size="-1"><span style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
+ size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1717,13 +1717,13 @@ normal,
-
- </span></font><small><span style="font-family: monospace;">Video
- encode output as (16-235)/255 "TV" levels</span></small><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#n">-n</a><span
+
+ </span></font><small><span style="font-family: monospace;">Video
+ encode output as (16-235)/255 "TV" levels</span></small><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#n">-n</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
[X11
@@ -1779,14 +1779,14 @@ on
-
- test window<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#J">-J</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Run instrument calibration first<br>
- </span></font><font size="-1"><span style="font-family:
+
+ test window<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#J">-J</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Run instrument calibration first<br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1834,18 +1834,18 @@ on
-
- Disable initial calibration of instrument if possible</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#H">-H</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
- available)<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;"></span><span style="font-family: monospace;"><br>
- &nbsp;</span></font><font size="-1"><span style="font-family:
- monospace;"><span style="text-decoration: underline;"></span><a
+
+ Disable initial calibration of instrument if possible</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#H">-H</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
+ available)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"><br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><span style="text-decoration: underline;"></span><a
href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1893,9 +1893,9 @@ on
-
- Apply Colorimeter Correction Matrix</span></font><br>
- <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
+
+ Apply Colorimeter Correction Matrix</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Use
Colorimeter
@@ -1946,14 +1946,14 @@ Calibration
-
- Spectral Samples for calibration</span><font size="-1"><span
- style="font-family: monospace;"><br>
- </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
- style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
- colorimeter data:</span><br style="font-family: monospace;">
+
+ Spectral Samples for calibration</span><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
+ colorimeter data:</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2001,11 +2001,11 @@ Calibration
-
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
- style="font-family: monospace;">(def.)</span></small><small><span
- style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
- J&amp;V 1978_2, 1964_10c<br>
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
+ style="font-family: monospace;">(def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2, 1964_10c<br>
&nbsp;<a href="#I">-I b|w</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2053,8 +2053,8 @@ Calibration
-
- Drift compensation, Black: -Ib, White: -Iw, Both: -Ibw</span></small><br>
+
+ Drift compensation, Black: -Ib, White: -Iw, Both: -Ibw</span></small><br>
<small><span style="font-family: monospace;"><tt>&nbsp;<a href="#YR">-Y
@@ -2071,7 +2071,7 @@ Calibration
-
+
R:<i>rate</i></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2088,36 +2088,36 @@ Calibration
-
- Override measured refresh rate with rate Hz<br>
- </tt>&nbsp;</span></small><font size="-1"><span
- style="font-family: monospace;"></span><a style=" font-family:
- monospace;" href="#YA">-<font size="-1">Y</font> A</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; Use non-adaptive integration time mode (if
- available).</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style=" font-family: monospace;" href="#Yp">-<font size="-1">Y</font>
- <font size="-1">p</font></a><span style="font-family:
- monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; Don't wait for the instrument to be placed on
- the display</span></font><br>
- <small><span style="font-family: monospace;"> </span></small><font
- size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#C">-C "command"</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
- "command" each time a color is set</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#M">-M "command"</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
- "command" each time a color is measured</span></font><font
- size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ Override measured refresh rate with rate Hz<br>
+ </tt>&nbsp;</span></small><font size="-1"><span
+ style="font-family: monospace;"></span><a style=" font-family:
+ monospace;" href="#YA">-<font size="-1">Y</font> A</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Use non-adaptive integration time mode (if
+ available).</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#Yp">-<font size="-1">Y</font>
+ <font size="-1">p</font></a><span style="font-family:
+ monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Don't wait for the instrument to be placed on
+ the display</span></font><br>
+ <small><span style="font-family: monospace;"> </span></small><font
+ size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#C">-C "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is set</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#M">-M "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is measured</span></font><font
+ size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
serial
@@ -2173,12 +2173,12 @@ none,
-
- h = HW, x = Xon/Xoff</span></font><font size="-1"><span
- style="font-family: monospace;"></span></font><br>
- <font size="-1"><span style="font-family: monospace;"> </span></font><font
- size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#D">-D [level]</a><span
+
+ h = HW, x = Xon/Xoff</span></font><font size="-1"><span
+ style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;"> </span></font><font
+ size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D [level]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2226,12 +2226,12 @@ none,
-
- Print debug diagnostics to stderr</span></font><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#p1"><i>inoutfile</i></a><span
+
+ Print debug diagnostics to stderr</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p1"><i>inoutfile</i></a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2279,79 +2279,79 @@ none,
-
- </span><span style="font-family: monospace;">Base name for created
- or updated </span></font><font size="-1"><a style="font-family:
- monospace;" href="cal_format.html">.cal</a><span
- style="font-family: monospace;"></span></font><font size="-1"><span
- style="font-family: monospace;">&nbsp; and <a
- href="File_Formats.html#ICC">.icm</a> output files</span></font><br>
- <br>
- <h3>Comments<br>
- </h3>
- This is the tool is used for adjusting and calibrating a display to
- reach specified target behaviour, and optionally profiling it.&nbsp;
- For best results on a CRT, you should run this against a neutral
- grey desktop background, and avoid having any bright images or
- windows on the screen at the time you run dispcal. You could also
- use the <span style="font-weight: bold;">-B</span> option to black
- the whole screen out, although this will make it impossible to
- control dispcal unless you have more than one display.<br>
- <br>
- <a name="v"></a> The <b>-v</b> flag reports progress information,
- as well as other statistics about the progress of calibration. A
- numerical argument greater than 1 gives greater verbosity. 2 will
- give per step adjustment and repeat information, while 3 will give
- even greater technical detail.<br>
- <br>
- <a name="display"></a>When running on a UNIX based system that used
- the X11 Windowing System, <b>dispcal</b> will by default use the
- $DISPLAY environment variable to determine which local or remote
- display and screen to read from. This can be overridden by supplying
- an X11 display name to the <span style="font-weight: bold;">-display</span>
- option. Note that if Xinerama is active, you can't select the screen
- using $DISPLAY or -display, you have to select it using the <span
- style="font-weight: bold;">-d</span> parameter.<br>
- <br>
- <a name="d"></a> By default the main display will be the location of
- the test window. If the system has more than one display or screen,
- an alternate display/screen can be selected with the <span
- style="font-weight: bold;">-d</span> parameter. If you invoke <span
- style="font-weight: bold;">dispcal</span> so as to display the
- usage information (i.e. "dispcal -?" or "dispcal --"), then the
- discovered displays/screens will be listed. Multiple displays may
- not be listed, if they appear as a single display to the operating
- system (ie. the multi-display support is hidden in the video card
- driver). On UNIX based system that used the X11 Windowing System,
- the <span style="font-weight: bold;">-d</span> parameter will
- override the screen specified by the $DISPLAY or parameter.<br>
- <br>
- <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
- display are not accessible (i.e. no hardware calibration
- capability), <span style="font-weight: bold;">dispcal</span> will
- will issue a warning, but continue creating a calibration based on
- the display "as-is" rather than its native response. See the <a
- href="dispcal.html#o">-o</a> flag for an explanation of the
- implications of having no access to the VideoLUTs.<br>
- <br>
- On X11 the inability to access VideoLUTs could be because you are
- trying to access a remote display, and the remote display doesn't
- support the XF86VidMode extension, or perhaps you are running
- multiple monitors using NVidia TwinView, or MergedFB, and trying to
- access anything other than the primary monitor. TwinView and
- MergedFB don't properly support the XF86VidMode extension for
- multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
- to test whether the VideoLUTs are accessible for a particular
- display. See also below, on how to select a different display for
- VideoLUT access. Also note that dispcal will fail if the Visual
- depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
- 256 entries per color component, so the Visual generally needs to be
- 24 bits, 8 bits per color component.<br>
- <br>
- <a name="dnm"></a>Because of the difficulty cause by TwinView and
- MergedFB in X11 based systems, you can optionally specify a separate
- display number after the display that is going to be used to present
- test patches, for accessing the VideoLUT hardware. This must be
+
+ </span><span style="font-family: monospace;">Base name for created
+ or updated </span></font><font size="-1"><a style="font-family:
+ monospace;" href="cal_format.html">.cal</a><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;">&nbsp; and <a
+ href="File_Formats.html#ICC">.icm</a> output files</span></font><br>
+ <br>
+ <h3>Comments<br>
+ </h3>
+ This is the tool is used for adjusting and calibrating a display to
+ reach specified target behaviour, and optionally profiling it.&nbsp;
+ For best results on a CRT, you should run this against a neutral
+ grey desktop background, and avoid having any bright images or
+ windows on the screen at the time you run dispcal. You could also
+ use the <span style="font-weight: bold;">-B</span> option to black
+ the whole screen out, although this will make it impossible to
+ control dispcal unless you have more than one display.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag reports progress information,
+ as well as other statistics about the progress of calibration. A
+ numerical argument greater than 1 gives greater verbosity. 2 will
+ give per step adjustment and repeat information, while 3 will give
+ even greater technical detail.<br>
+ <br>
+ <a name="display"></a>When running on a UNIX based system that used
+ the X11 Windowing System, <b>dispcal</b> will by default use the
+ $DISPLAY environment variable to determine which local or remote
+ display and screen to read from. This can be overridden by supplying
+ an X11 display name to the <span style="font-weight: bold;">-display</span>
+ option. Note that if Xinerama is active, you can't select the screen
+ using $DISPLAY or -display, you have to select it using the <span
+ style="font-weight: bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a> By default the main display will be the location of
+ the test window. If the system has more than one display or screen,
+ an alternate display/screen can be selected with the <span
+ style="font-weight: bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispcal</span> so as to display the
+ usage information (i.e. "dispcal -?" or "dispcal --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed, if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or parameter.<br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
+ display are not accessible (i.e. no hardware calibration
+ capability), <span style="font-weight: bold;">dispcal</span> will
+ will issue a warning, but continue creating a calibration based on
+ the display "as-is" rather than its native response. See the <a
+ href="dispcal.html#o">-o</a> flag for an explanation of the
+ implications of having no access to the VideoLUTs.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
+ <a name="dnm"></a>Because of the difficulty cause by TwinView and
+ MergedFB in X11 based systems, you can optionally specify a separate
+ display number after the display that is going to be used to present
+ test patches, for accessing the VideoLUT hardware. This must be
specified as a single string, e.g. <span style="font-weight: bold;">-d
@@ -2399,273 +2399,273 @@ none,
-
- 1,2</span> . Some experimentation may be needed using <a
- href="dispwin.html">dispwin</a> on such systems, to discover what
- screen has access to the VideoLUT hardware, and which screens the
- test patches appear on. You may be able to calibrate one screen, and
- then share the calibration with another screen. Profiling can be
- done independently to calibration on each screen.<br>
- <br>
- <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
- <span style="font-weight: bold;">-dweb:port</span> starts a
- standalone web server on your machine, which then allows a local or
- remote web browser to display the the color test patches. By default
- port <span style="font-weight: bold;">8080</span> is used, but this
- can be overridden by appending a <span style="font-weight: bold;">:</span>
- and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
- The URL will be <span style="font-weight: bold;">http://</span>
- then name of the machine or its I.P. address followed by a colon and
- the port number - e.g something like <span style="font-weight:
- bold;">http://192.168.0.1:8080</span>. If you use the verbose
- option (<span style="font-weight: bold;">-v</span>) then a likely
- URL will be printed once the server is started, or you could run <span
- style="font-weight: bold;">ipconfig</span> (MSWin) or <span
- style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
- and identify an internet address for your machine that way. <b>JavaScript</b>
- needs to be enabled in your web browser for this to work. You may
- have to modify any firewall to permit port 8080 to be accessed on
- your machine.<br>
- <br>
- Note that if you use this method of displaying test patches, that
- there is no access to the display VideoLUTs and that the colors will
- be displayed with 8 bit per component precision, and any
- screen-saver or power-saver will not be disabled. You will also be
- at the mercy of any color management applied by the web browser, and
- may have to carefully review and configure such color management.
- See the <a href="#o">-o</a> flag for an explanation of the
- implications of having no access to the VideoLUTs.<br>
- <br>
- <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
- [MSWin only] causes test patches to be displayed using the MadVR
- video renderer. Note that will have to start <b>MadTPG</b> before
- running dispcal, and that while you can adjust the "Test Pattern
- Configuration" controls, you should <u>not</u> normally alter the
- "Existing Calibration" controls, as dispcal will set these
- appropriately. <br>
- <br>
- <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
- causes test patches to be displayed using and available <a
- href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
- your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
- local network. Note that the ChromeCast as a test patch source is
- probably the<b> least accurate</b> of your choices, since it
- up-samples the test patch and transforms from RGB to YCC and back,
- but should be accurate within ± 1 bit. You may have to modify any
- firewall to permit port 8081 to be accessed on your machine if it
+
+ 1,2</span> . Some experimentation may be needed using <a
+ href="dispwin.html">dispwin</a> on such systems, to discover what
+ screen has access to the VideoLUT hardware, and which screens the
+ test patches appear on. You may be able to calibrate one screen, and
+ then share the calibration with another screen. Profiling can be
+ done independently to calibration on each screen.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:port</span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way. <b>JavaScript</b>
+ needs to be enabled in your web browser for this to work. You may
+ have to modify any firewall to permit port 8080 to be accessed on
+ your machine.<br>
+ <br>
+ Note that if you use this method of displaying test patches, that
+ there is no access to the display VideoLUTs and that the colors will
+ be displayed with 8 bit per component precision, and any
+ screen-saver or power-saver will not be disabled. You will also be
+ at the mercy of any color management applied by the web browser, and
+ may have to carefully review and configure such color management.
+ See the <a href="#o">-o</a> flag for an explanation of the
+ implications of having no access to the VideoLUTs.<br>
+ <br>
+ <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
+ [MSWin only] causes test patches to be displayed using the MadVR
+ video renderer. Note that will have to start <b>MadTPG</b> before
+ running dispcal, and that while you can adjust the "Test Pattern
+ Configuration" controls, you should <u>not</u> normally alter the
+ "Existing Calibration" controls, as dispcal will set these
+ appropriately. <br>
+ <br>
+ <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
+ causes test patches to be displayed using and available <a
+ href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
+ your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
+ local network. Note that the ChromeCast as a test patch source is
+ probably the<b> least accurate</b> of your choices, since it
+ up-samples the test patch and transforms from RGB to YCC and back,
+ but should be accurate within ± 1 bit. You may have to modify any
+ firewall to permit port 8081 to be accessed on your machine if it
falls back to the Default receiver (see <a href="Installing.html">installation
-
- instructions</a> for your platform).<br>
- <br>
- <a name="c"></a> <span style="font-weight: bold;">-c</span> The
- instrument is assumed to communicate through a USB or serial
- communication port, and the port can be selected with the <b>-c</b>
- option, if the instrument is not connected to the first port. If you
- invoke <span style="font-weight: bold;">dispcal</span> so as to
- display the usage information (i.e. "dispcal -?" or "dispcal --"),
- then the discovered USB and serial ports will be listed. On
- UNIX/Linux, a list of all possible serial ports are shown, but not
- all of them may actually be present on your system.<br>
- <br>
- <a name="r"></a> The -<span style="font-weight: bold;">r</span> and
- <span style="font-weight: bold;"><a name="R"></a>-R </span>flags
- perform a quick measurement of current display behaviour, reports
- and then exits. If the <span style="font-weight: bold;">-r</span>
- flag is used the measurement are taken using the currently loaded
- calibration (Video LUT) curves, and in the case of MadVR renderer
- test patch display the Color Management 3dLut. If <span
- style="font-weight: bold;">-R</span> is use, then the uncalibrated
- ("raw" or "native") behaviour is measured (ie. no VideoLut or CM).
- Reported are: <br>
- <br>
- &nbsp;&nbsp;&nbsp; Black Brightness in cd/m^2<br>
- &nbsp;&nbsp;&nbsp; White Brightness in cd/m^2<br>
- &nbsp;&nbsp;&nbsp; The approximate Gamma<br>
- &nbsp;&nbsp;&nbsp; The white point x,y chromaticity co-ordinates<br>
- &nbsp;&nbsp;&nbsp; The correlated color temperature in Kelvin, and
- the CIEDE200 to the Black Body locus.<br>
- &nbsp;&nbsp;&nbsp; The correlated Daylight temperature in Kelvin,
- and the CIEDE200 to the Daylight locus.<br>
- &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin, and the
- CIEDE200 to the Black Body locus.<br>
- &nbsp;&nbsp;&nbsp; The visual Daylight temperature in Kelvin, and
- the CIEDE200 to the Daylight locus.<br>
- &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin<br>
- (for <span style="font-weight: bold;">-R </span>"raw":)<br>
- &nbsp;&nbsp;&nbsp; The apparent VideoLUT entry number of significant
- bits.<br>
- <br>
- Note that the correlated color temperature is the temperature of a
- black body radiator that has the closest color to the white point
- measured using the traditional CIE 1960 UCS space color difference
- formula. The correlated daylight temperature is a similar thing,
- except the CIE daylight locus is used. The visual color temperature
- values are calculated similarly to the correlated color
- temperatures, but using the modern CIEDE2000 color difference
- formula to calculate a better visual approximation to the closest
- temperature to the displays white point. There will be no difference
- between the UCS and CIEDE2000 temperatures if the display white
- point actually lies on the particular locus.<br>
- <br>
- <a name="m"></a> The -<span style="font-weight: bold;">m</span>
- option skips the usual process of adjusting the display monitor
- contrast, brightness and white point controls, and skips straight to
- calibration.<br>
- <br>
- <a name="o"></a><span style="font-weight: bold;">-o [</span><span
- style="font-style: italic;">profile.icm</span><span
- style="font-weight: bold;">]</span> Normally <span
- style="font-weight: bold;">dispcal</span> creates just a
- calibration file, which can then be used for subsequent
- characterization using <a href="dispread.html">dispread</a> and
- profiling using <a href="colprof.html">colprof</a>. If the <span
- style="font-weight: bold;">-o</span> flag is used, <span
- style="font-weight: bold;">dispcal</span> will also create a
- shaper/matrix profile. By default it will create a profile named <span
- style="font-weight: bold;">inoutfile.icm</span>, but a differently
- named file can be created or updated by specifying the name after
- the <span style="font-weight: bold;">-o</span> flag. If the <span
- style="font-weight: bold;">-u</span> flag is used with <span
- style="font-weight: bold;">-o</span>, then the ICC profile <span
- style="font-weight: bold;">vcgt</span> calibration curves will be
- updated.<br>
- <br>
- Note that if VideoLUT access is not possible for the display, that
- hardware calibration is not possible. dispcal will create
- calibration curves anyway with a warning, and if a profile is
- created, it will not contain a 'vcgt' tag, but instead will have the
- calibration curves incorporated into the profile itself. If
- calibration parameters are chosen that change the displays white
- point or brightness, then this will result in a slightly unusual
- profile that has a white point that does not correspond with
- R=G=B=1.0. Some systems may not cope properly with this type of
- profile. See the <a href="Scenarios.html#PM7">tutorial</a> for a
- further explanation.<br>
- <br>
- <a name="O"></a>The <b>-O</b> parameter allows setting of the
- shaper/matrix profile description tag. The parameter should be a
- string that describes the device and profile. With most command line
- shells, it will be necessary to enclose the parameter with double
- quotes, so that spaces and other special characters are included in
- the parameter, and not mistaken for the start of another flag, or as
- a final command line parameter. Many programs that deal with ICC
- profiles use the description tag to identify a profile, rather than
- the profile filename, so using a descriptive string is important in
- being able to find a profile. By default, the profile file name will
- be used as the description.<br>
- <br>
- <a name="u"></a><span style="font-weight: bold;">-u</span> Normally
- <span style="font-weight: bold;">dispcal</span> creates a new
- calibration file and optional profile, based on the requested
- targets and the response of the display. This can take a fair amount
- of time, particularly if a high quality level has been selected, so
- to speed up the process of keeping a display in calibration the <span
- style="font-weight: bold;">-u</span> flag can be used. This uses
- the same calibration targets as the previous calibration but does a
- smaller number of refinement passes, enough to improve the accuracy
- of the calibration to account for drift in the device. If the <span
- style="font-weight: bold;">-o</span> flag is used as well, then
- the ICC profile <span style="font-weight: bold;"></span>will have
- its vcgt tag updated with the new calibration. This keeps the
- profile up to date with the display. Normally <span
- style="font-weight: bold;">dispcal -u</span> will use the same
- quality level that was specified in the previous calibration, but
- this can be overridden using the <span style="font-weight: bold;">-q</span>
- flag. Any options that attempt to change the calibration target (ie.
- white point, brightness, gamma etc.) will be ignored. Adjustment of
- the display monitor controls is skipped. A profile cannot be updated
- if the display does not support hardware calibration (no VideoLUT
- access).<br>
- <br>
- <a name="q"></a>&nbsp; Quality - Low, Medium (def), High. The <span
- style="font-weight: bold;">-q</span> flag determines how much time
- and effort to go to in calibrating the display. The higher the
- quality, the more test readings will be done, the more refinement
- passes will be done, the tighter will be the accuracy tolerance, and
- the more detailed will be the calibration of the display. The result
- will ultimately be limited by the accuracy of the instrument, the
- repeatability of the display and instrument, and the resolution of
- the Video Lookup table entries and Digital or Analogue output
- (RAMDAC).<br>
- <br>
- <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
- allows measuring in telephoto mode, using instruments that support
- this mode, e.g. the ColorMunki. Telephoto mode is one for taking
- emissive measurements from a distance (ie. telespectometer,
- tele-colorimeter) mode, and typically would be used for measuring
- projector type displays. If a device does not support a specific
- telephoto mode, then the normal emissive mode may be suitable for
- measuring projectors.<br>
- <br>
- <a name="y"></a>&nbsp; The <span style="font-weight: bold;">-y</span>
- flag allows setting the Display Type. The selection typically
- determines two aspects of of the instrument operation: <span
- style="font-weight: bold;">1)</span> It may set the measuring mode
- to suite <a
- href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
- style="font-weight: bold;">refresh</span> or <span
- style="font-weight: bold;">non-refresh</span> displays</a>.
- Typically only LCD (Liquid Crystal) displays have a non-refresh
- nature. <span style="font-weight: bold;">2)</span> It may select an
- instrument calibration matrix suitable for a particular display
- type. The selections available depends on the type and model of
- instrument, and a list of the options for the discovered instruments
- will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
- information. For more details on what particular instruments support
- and how this works, see <a href="instruments.html">Operation of
- particular instruments</a>. <b>3)</b> Any installed CCSS files
- (if applicable), or CCMX files. These files are typically created
- using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
- href="oeminst.html">oeminst</a>. The default and Base Calibration
- types will be indicated in the usage.<br>
- <br>
- <a name="t"></a><span style="text-decoration: underline;"></span> <span
- style="font-weight: bold;">-t</span> Set the target white point
- locus to the equivalent of a Daylight spectrum of the given
- temperature in degrees Kelvin. By default the white point target
- will be the native white of the display, and it's color temperature
- and delta E to the daylight spectrum locus will be shown during
- monitor adjustment, and adjustments will be recommended to put the
- display white point directly on the Daylight locus. If a Daylight
- color temperature is given as an argument to <span
- style="font-weight: bold;">-t</span>, then this will become the
- target of the adjustment, and the recommended adjustments will be
- those needed to make the monitor white point meet the target.
- Typical&nbsp; values might be 5000 for matching printed output, or
- 6500, which gives a brighter, bluer look. A white point temperature
- different to that native to the display may limit the maximum
- brightness possible.<br>
- <br>
- <a name="T"></a><span style="text-decoration: underline;"></span> <span
- style="font-weight: bold;">-T</span>&nbsp; Same functionality as
- the <span style="font-weight: bold;">-t</span> option, except the
- white point locus will be the Black Body, or Planckian locus, rather
- than the Daylight locus. While these two white point loci are quite
- close, they are subtly different. If a temperature is given as an
- argument, this will become the Black Body target temperature during
- adjustment.<br>
- <br>
- <a name="w"></a><span style="font-weight: bold;">-w</span>&nbsp; An
- alternative to specifying a&nbsp; white point target in Daylight or
- Black Body degrees Kevin, is to specify it in chromaticity
- co-ordinates. This allows the white point to be a color other than
- one on the Daylight or Black Body. Note that the x,y numbers must be
- specified as a single string (no space between the numbers and the
- comma).<br>
- <br>
- <a name="b"></a><span style="font-weight: bold;">-b</span>&nbsp; Set
- the target brightness of white in cd/m^2. If this number cannot be
- reached, the brightest output possible is chosen, consistent with
- matching the white point target. Note that many of the instruments
- are not particularly accurate when assessing the absolute display
- brightness in cd/m^2. <span style="font-weight: bold;">NOTE</span>
- that some LCD screens behave a little strangely near their absolute
- white point, and may therefore exhibit odd behavior at values just
- below white. It may be advisable in such cases to set a brightness
- slightly less than the maximum such a display is capable of.<br>
- <br>
+
+ instructions</a> for your platform).<br>
+ <br>
+ <a name="c"></a> <span style="font-weight: bold;">-c</span> The
+ instrument is assumed to communicate through a USB or serial
+ communication port, and the port can be selected with the <b>-c</b>
+ option, if the instrument is not connected to the first port. If you
+ invoke <span style="font-weight: bold;">dispcal</span> so as to
+ display the usage information (i.e. "dispcal -?" or "dispcal --"),
+ then the discovered USB and serial ports will be listed. On
+ UNIX/Linux, a list of all possible serial ports are shown, but not
+ all of them may actually be present on your system.<br>
+ <br>
+ <a name="r"></a> The -<span style="font-weight: bold;">r</span> and
+ <span style="font-weight: bold;"><a name="R"></a>-R </span>flags
+ perform a quick measurement of current display behaviour, reports
+ and then exits. If the <span style="font-weight: bold;">-r</span>
+ flag is used the measurement are taken using the currently loaded
+ calibration (Video LUT) curves, and in the case of MadVR renderer
+ test patch display the Color Management 3dLut. If <span
+ style="font-weight: bold;">-R</span> is use, then the uncalibrated
+ ("raw" or "native") behaviour is measured (ie. no VideoLut or CM).
+ Reported are: <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Black Brightness in cd/m^2<br>
+ &nbsp;&nbsp;&nbsp; White Brightness in cd/m^2<br>
+ &nbsp;&nbsp;&nbsp; The approximate Gamma<br>
+ &nbsp;&nbsp;&nbsp; The white point x,y chromaticity co-ordinates<br>
+ &nbsp;&nbsp;&nbsp; The correlated color temperature in Kelvin, and
+ the CIEDE200 to the Black Body locus.<br>
+ &nbsp;&nbsp;&nbsp; The correlated Daylight temperature in Kelvin,
+ and the CIEDE200 to the Daylight locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin, and the
+ CIEDE200 to the Black Body locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual Daylight temperature in Kelvin, and
+ the CIEDE200 to the Daylight locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin<br>
+ (for <span style="font-weight: bold;">-R </span>"raw":)<br>
+ &nbsp;&nbsp;&nbsp; The apparent VideoLUT entry number of significant
+ bits.<br>
+ <br>
+ Note that the correlated color temperature is the temperature of a
+ black body radiator that has the closest color to the white point
+ measured using the traditional CIE 1960 UCS space color difference
+ formula. The correlated daylight temperature is a similar thing,
+ except the CIE daylight locus is used. The visual color temperature
+ values are calculated similarly to the correlated color
+ temperatures, but using the modern CIEDE2000 color difference
+ formula to calculate a better visual approximation to the closest
+ temperature to the displays white point. There will be no difference
+ between the UCS and CIEDE2000 temperatures if the display white
+ point actually lies on the particular locus.<br>
+ <br>
+ <a name="m"></a> The -<span style="font-weight: bold;">m</span>
+ option skips the usual process of adjusting the display monitor
+ contrast, brightness and white point controls, and skips straight to
+ calibration.<br>
+ <br>
+ <a name="o"></a><span style="font-weight: bold;">-o [</span><span
+ style="font-style: italic;">profile.icm</span><span
+ style="font-weight: bold;">]</span> Normally <span
+ style="font-weight: bold;">dispcal</span> creates just a
+ calibration file, which can then be used for subsequent
+ characterization using <a href="dispread.html">dispread</a> and
+ profiling using <a href="colprof.html">colprof</a>. If the <span
+ style="font-weight: bold;">-o</span> flag is used, <span
+ style="font-weight: bold;">dispcal</span> will also create a
+ shaper/matrix profile. By default it will create a profile named <span
+ style="font-weight: bold;">inoutfile.icm</span>, but a differently
+ named file can be created or updated by specifying the name after
+ the <span style="font-weight: bold;">-o</span> flag. If the <span
+ style="font-weight: bold;">-u</span> flag is used with <span
+ style="font-weight: bold;">-o</span>, then the ICC profile <span
+ style="font-weight: bold;">vcgt</span> calibration curves will be
+ updated.<br>
+ <br>
+ Note that if VideoLUT access is not possible for the display, that
+ hardware calibration is not possible. dispcal will create
+ calibration curves anyway with a warning, and if a profile is
+ created, it will not contain a 'vcgt' tag, but instead will have the
+ calibration curves incorporated into the profile itself. If
+ calibration parameters are chosen that change the displays white
+ point or brightness, then this will result in a slightly unusual
+ profile that has a white point that does not correspond with
+ R=G=B=1.0. Some systems may not cope properly with this type of
+ profile. See the <a href="Scenarios.html#PM7">tutorial</a> for a
+ further explanation.<br>
+ <br>
+ <a name="O"></a>The <b>-O</b> parameter allows setting of the
+ shaper/matrix profile description tag. The parameter should be a
+ string that describes the device and profile. With most command line
+ shells, it will be necessary to enclose the parameter with double
+ quotes, so that spaces and other special characters are included in
+ the parameter, and not mistaken for the start of another flag, or as
+ a final command line parameter. Many programs that deal with ICC
+ profiles use the description tag to identify a profile, rather than
+ the profile filename, so using a descriptive string is important in
+ being able to find a profile. By default, the profile file name will
+ be used as the description.<br>
+ <br>
+ <a name="u"></a><span style="font-weight: bold;">-u</span> Normally
+ <span style="font-weight: bold;">dispcal</span> creates a new
+ calibration file and optional profile, based on the requested
+ targets and the response of the display. This can take a fair amount
+ of time, particularly if a high quality level has been selected, so
+ to speed up the process of keeping a display in calibration the <span
+ style="font-weight: bold;">-u</span> flag can be used. This uses
+ the same calibration targets as the previous calibration but does a
+ smaller number of refinement passes, enough to improve the accuracy
+ of the calibration to account for drift in the device. If the <span
+ style="font-weight: bold;">-o</span> flag is used as well, then
+ the ICC profile <span style="font-weight: bold;"></span>will have
+ its vcgt tag updated with the new calibration. This keeps the
+ profile up to date with the display. Normally <span
+ style="font-weight: bold;">dispcal -u</span> will use the same
+ quality level that was specified in the previous calibration, but
+ this can be overridden using the <span style="font-weight: bold;">-q</span>
+ flag. Any options that attempt to change the calibration target (ie.
+ white point, brightness, gamma etc.) will be ignored. Adjustment of
+ the display monitor controls is skipped. A profile cannot be updated
+ if the display does not support hardware calibration (no VideoLUT
+ access).<br>
+ <br>
+ <a name="q"></a>&nbsp; Quality - Low, Medium (def), High. The <span
+ style="font-weight: bold;">-q</span> flag determines how much time
+ and effort to go to in calibrating the display. The higher the
+ quality, the more test readings will be done, the more refinement
+ passes will be done, the tighter will be the accuracy tolerance, and
+ the more detailed will be the calibration of the display. The result
+ will ultimately be limited by the accuracy of the instrument, the
+ repeatability of the display and instrument, and the resolution of
+ the Video Lookup table entries and Digital or Analogue output
+ (RAMDAC).<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ allows measuring in telephoto mode, using instruments that support
+ this mode, e.g. the ColorMunki. Telephoto mode is one for taking
+ emissive measurements from a distance (ie. telespectometer,
+ tele-colorimeter) mode, and typically would be used for measuring
+ projector type displays. If a device does not support a specific
+ telephoto mode, then the normal emissive mode may be suitable for
+ measuring projectors.<br>
+ <br>
+ <a name="y"></a>&nbsp; The <span style="font-weight: bold;">-y</span>
+ flag allows setting the Display Type. The selection typically
+ determines two aspects of of the instrument operation: <span
+ style="font-weight: bold;">1)</span> It may set the measuring mode
+ to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument calibration matrix suitable for a particular display
+ type. The selections available depends on the type and model of
+ instrument, and a list of the options for the discovered instruments
+ will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. <b>3)</b> Any installed CCSS files
+ (if applicable), or CCMX files. These files are typically created
+ using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
+ href="oeminst.html">oeminst</a>. The default and Base Calibration
+ types will be indicated in the usage.<br>
+ <br>
+ <a name="t"></a><span style="text-decoration: underline;"></span> <span
+ style="font-weight: bold;">-t</span> Set the target white point
+ locus to the equivalent of a Daylight spectrum of the given
+ temperature in degrees Kelvin. By default the white point target
+ will be the native white of the display, and it's color temperature
+ and delta E to the daylight spectrum locus will be shown during
+ monitor adjustment, and adjustments will be recommended to put the
+ display white point directly on the Daylight locus. If a Daylight
+ color temperature is given as an argument to <span
+ style="font-weight: bold;">-t</span>, then this will become the
+ target of the adjustment, and the recommended adjustments will be
+ those needed to make the monitor white point meet the target.
+ Typical&nbsp; values might be 5000 for matching printed output, or
+ 6500, which gives a brighter, bluer look. A white point temperature
+ different to that native to the display may limit the maximum
+ brightness possible.<br>
+ <br>
+ <a name="T"></a><span style="text-decoration: underline;"></span> <span
+ style="font-weight: bold;">-T</span>&nbsp; Same functionality as
+ the <span style="font-weight: bold;">-t</span> option, except the
+ white point locus will be the Black Body, or Planckian locus, rather
+ than the Daylight locus. While these two white point loci are quite
+ close, they are subtly different. If a temperature is given as an
+ argument, this will become the Black Body target temperature during
+ adjustment.<br>
+ <br>
+ <a name="w"></a><span style="font-weight: bold;">-w</span>&nbsp; An
+ alternative to specifying a&nbsp; white point target in Daylight or
+ Black Body degrees Kevin, is to specify it in chromaticity
+ co-ordinates. This allows the white point to be a color other than
+ one on the Daylight or Black Body. Note that the x,y numbers must be
+ specified as a single string (no space between the numbers and the
+ comma).<br>
+ <br>
+ <a name="b"></a><span style="font-weight: bold;">-b</span>&nbsp; Set
+ the target brightness of white in cd/m^2. If this number cannot be
+ reached, the brightest output possible is chosen, consistent with
+ matching the white point target. Note that many of the instruments
+ are not particularly accurate when assessing the absolute display
+ brightness in cd/m^2. <span style="font-weight: bold;">NOTE</span>
+ that some LCD screens behave a little strangely near their absolute
+ white point, and may therefore exhibit odd behavior at values just
+ below white. It may be advisable in such cases to set a brightness
+ slightly less than the maximum such a display is capable of.<br>
+ <br>
<a name="g"></a><span style="font-weight: bold;">-g gamma</span>&nbsp;
Set
@@ -2714,14 +2714,14 @@ Set
-
- the target response curve gamma. This is normally an exponential
- curve (output = input ^gamma), and defaults to 2.4 on MSWindows and
- Macintosh OS X 10.6 or latter and Linux/Unix (which is typical of a
- CRT type displays real response), and 1.8 on a Macintosh (prior to
- OS X 10.6). Four pre-defined curves can be used as well: the sRGB
- colorspace response curve, which is an exponent curve with a
- straight segment at the dark end and an overall response of
+
+ the target response curve gamma. This is normally an exponential
+ curve (output = input ^gamma), and defaults to 2.4 on MSWindows and
+ Macintosh OS X 10.6 or latter and Linux/Unix (which is typical of a
+ CRT type displays real response), and 1.8 on a Macintosh (prior to
+ OS X 10.6). Four pre-defined curves can be used as well: the sRGB
+ colorspace response curve, which is an exponent curve with a
+ straight segment at the dark end and an overall response of
approximately gamma 2.2 (<span style="font-weight: bold;">-gs</span>),
the
@@ -2770,65 +2770,65 @@ the
-
- L* curve, which is the response of the CIE L*a*b* perceptual
- colorspace (<span style="font-weight: bold;">-gl</span>). the REC
- 709 video standard response curve (<span style="font-weight: bold;">-g709</span>)
- and the SMPTE 240M video standard response curve (<span
- style="font-weight: bold;">-g240</span>) <br>
- <br>
- <span style="font-weight: bold;">Note</span> that a real display
- can't reproduce any of these ideal curves, since it will have a
- non-zero black point, whereas all the ideal curves assume zero light
- at zero input. In the case of a gamma curve target, dispcal uses an
- actual technical power curve shape that aims for the same relative
- output at 50% input as the ideal gamma power curve. To allow for the
- non-zero black level of a real display, by default <span
- style="font-weight: bold;">dispcal</span> will offset the target
- curve values so that zero input gives the actual black level of the
- display (output offset). This ensures that the target curve better
- corresponds to the typical natural behavior of displays, but it may
- not be the most visually even progression from display minimum, but
- this behavior can be changed using the <span style="font-weight:
- bold;">-f</span> option (see below).<br>
- <br>
- <span style="font-weight: bold;">Also note</span> that many color
- spaces are encoded with, and labelled as having a gamma of
- approximately<span style="font-weight: bold;"> 2.2</span> (ie. sRGB,
- REC 709, SMPTE 240M, Macintosh OS X 10.6), but are actually intended
- to be displayed on a display with a typical CRT gamma of <span
- style="font-weight: bold;">2.4</span> viewed in a darkened
- environment. This is because this <span style="font-weight: bold;">2.2</span>
- gamma is a source gamma encoding in bright viewing conditions such
- as a television studio, while typical display viewing conditions are
- quite dark by comparison, and a contrast expansion of (approx.)
- gamma 1.1 is desirable to make the images look as intended. So if
- you are displaying images encoded to the sRGB standard, or
- displaying video through the calibration, just setting the gamma
- curve to sRGB or REC 709 (respectively) is probably <span
- style="font-weight: bold;">not what you want!</span> What you
- probably want to do, is to set the gamma curve to about gamma 2.4,
- so that the contrast range is expanded appropriately, or <span
- style="text-decoration: underline; font-weight: bold;">alternatively</span>
- use sRGB or REC 709 or a gamm of 2.2 but <span style="font-weight:
- bold;">also</span> use the <span style="font-weight: bold;">-a</span>
- parameter to specify the actual ambient viewing conditions, so that
- <span style="font-weight: bold;">dispcal</span> can make an
- appropriate contrast enhancement. If your instrument is capable of
- measuring ambient light levels, then you can do so during the
- interactive display control adjustment. See
- &lt;http://www.color.org/sRGB.xalter&gt; for details of how sRGB is
- intended to be used.<br>
- <br>
- It is hard to know whether Apple Macintosh computers prior to OS X
- 10.6 should also have such an adjustment, since it is not really
- possible to know whether colors labelled as being in such a
- colorspace are actually encoded in that gamma with the expectation
- that they will be displayed on a display with that actual response,
- or whether they are intended to be displayed on a display that
- contrast expands by a power 1.1.&nbsp; Both situations might be the
- case, depending on how source material is created!<br>
- <br>
+
+ L* curve, which is the response of the CIE L*a*b* perceptual
+ colorspace (<span style="font-weight: bold;">-gl</span>). the REC
+ 709 video standard response curve (<span style="font-weight: bold;">-g709</span>)
+ and the SMPTE 240M video standard response curve (<span
+ style="font-weight: bold;">-g240</span>) <br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that a real display
+ can't reproduce any of these ideal curves, since it will have a
+ non-zero black point, whereas all the ideal curves assume zero light
+ at zero input. In the case of a gamma curve target, dispcal uses an
+ actual technical power curve shape that aims for the same relative
+ output at 50% input as the ideal gamma power curve. To allow for the
+ non-zero black level of a real display, by default <span
+ style="font-weight: bold;">dispcal</span> will offset the target
+ curve values so that zero input gives the actual black level of the
+ display (output offset). This ensures that the target curve better
+ corresponds to the typical natural behavior of displays, but it may
+ not be the most visually even progression from display minimum, but
+ this behavior can be changed using the <span style="font-weight:
+ bold;">-f</span> option (see below).<br>
+ <br>
+ <span style="font-weight: bold;">Also note</span> that many color
+ spaces are encoded with, and labelled as having a gamma of
+ approximately<span style="font-weight: bold;"> 2.2</span> (ie. sRGB,
+ REC 709, SMPTE 240M, Macintosh OS X 10.6), but are actually intended
+ to be displayed on a display with a typical CRT gamma of <span
+ style="font-weight: bold;">2.4</span> viewed in a darkened
+ environment. This is because this <span style="font-weight: bold;">2.2</span>
+ gamma is a source gamma encoding in bright viewing conditions such
+ as a television studio, while typical display viewing conditions are
+ quite dark by comparison, and a contrast expansion of (approx.)
+ gamma 1.1 is desirable to make the images look as intended. So if
+ you are displaying images encoded to the sRGB standard, or
+ displaying video through the calibration, just setting the gamma
+ curve to sRGB or REC 709 (respectively) is probably <span
+ style="font-weight: bold;">not what you want!</span> What you
+ probably want to do, is to set the gamma curve to about gamma 2.4,
+ so that the contrast range is expanded appropriately, or <span
+ style="text-decoration: underline; font-weight: bold;">alternatively</span>
+ use sRGB or REC 709 or a gamm of 2.2 but <span style="font-weight:
+ bold;">also</span> use the <span style="font-weight: bold;">-a</span>
+ parameter to specify the actual ambient viewing conditions, so that
+ <span style="font-weight: bold;">dispcal</span> can make an
+ appropriate contrast enhancement. If your instrument is capable of
+ measuring ambient light levels, then you can do so during the
+ interactive display control adjustment. See
+ &lt;http://www.color.org/sRGB.xalter&gt; for details of how sRGB is
+ intended to be used.<br>
+ <br>
+ It is hard to know whether Apple Macintosh computers prior to OS X
+ 10.6 should also have such an adjustment, since it is not really
+ possible to know whether colors labelled as being in such a
+ colorspace are actually encoded in that gamma with the expectation
+ that they will be displayed on a display with that actual response,
+ or whether they are intended to be displayed on a display that
+ contrast expands by a power 1.1.&nbsp; Both situations might be the
+ case, depending on how source material is created!<br>
+ <br>
<a name="G"></a><span style="font-weight: bold;">-G gamma</span>&nbsp;
As
@@ -2877,99 +2877,99 @@ As
-
- explained above, the gamma value provided to the <span
- style="font-weight: bold;">-g</span> option is used to set and
- actual response curve that makes an allowance for the non-zero black
- of the actual display, and will have the same relative output at 50%
- input as the ideal gamma power curve, and so best matches typical
- expectations. The <span style="font-weight: bold;">-G</span> option
- is an alternative that allows the <span style="font-weight: bold;">actual</span>
- power to be specified instead, meaning that when combined with the
- displays non-zero black value, the response at 50% input will
- probably not match that of the ideal power curve with that gamma
- value.<br>
- <br>
- <a name="f"></a><span style="font-weight: bold;">-f [degree]</span>:
- As explained in for the <span style="font-weight: bold;">-g</span>
- and <span style="font-weight: bold;">-G</span> options, real
- displays do not have a zero black response, while all the target
- response curves do, so this has to be allowed for in some way. The
- default way of handling this (equivalent to -f 1.0)&nbsp; is to
- allow for this at the output of the ideal response curve, by
- offsetting and scaling the output values.<span style="font-weight:
- bold;"></span> This defined a curve that will match the responses
- that many other systems provide and may be a better match to the
- natural response of the display, but will give a less visually even
- response from black<span style="font-weight: bold;"></span>. The
- other alternative is to offset and scale the input values into the
- ideal response curve so that zero input gives the actual non-zero
- display response. This ensures the most visually even progression
- from display minimum, but might be hard to achieve since it is
- different to the naturally response of a display. A subtlety is to
- provide a split between how much of the offset is accounted for as
- input to the ideal response curve, and how much is accounted for at
- the output, and this can be done by providing a parameter <span
- style="font-weight: bold;">-f degree</span>, where the degree is
- 0.0 accounts for it all as input offset, and 1.0 accounts for all of
- it as output offset. If <span style="font-weight: bold;">-f</span>
- is used without a specified degree, a degree of 0.0 is assumed, the
- opposite of the default. <span style="font-weight: bold;">Note</span>
- that using all input offset (degree == 0.0) is equivalent to the use
- of the <span style="font-weight: bold;">BT.1886</span> transfer
- function.<br>
- <br>
- <a name="a"></a><span style="font-weight: bold;">-a ambient</span>:
- As explained for the <span style="font-weight: bold;">-g</span>
- parameter, often colors are encoded in a situation with viewing
- conditions that are quite different to the viewing conditions of a
- typical display, with the expectation that this difference in
- viewing conditions will be allowed for in the way the display is
- calibrated. The <span style="font-weight: bold;">-a</span> option
- is a way of doing this. By default <span style="font-weight: bold;">dispcal</span>
- will not make any allowances for viewing conditions, but will
- calibrate to the specified response curve, but if the <span
- style="font-weight: bold;">-a</span> option is used, or the
- ambient level is measured during the interactive display controls
- portion of the calibration, an appropriate viewing conditions
- adjustment will be performed. For a gamma value or sRGB, the
- original viewing conditions will be assumed to be that of the sRGB
- standard viewing conditions, while for REC 709 and SMPTE 240M they
- will be assumed to be television studio viewing conditions. By
- specifying or measuring the ambient lighting for your display, a
- viewing conditions adjustment based on the CIECAM02 color appearance
- model will be made for the brightness of&nbsp; your display and the
- contrast it makes with your ambient light levels. <br>
- <br>
- <a name="k"></a><span style="font-weight: bold;">-k factor</span>:
- Normally this will be set automatically, based on the measured black
- level of the display. A <span style="font-weight: bold;">-k</span>
- factor of 1.0 will make all colors down the neutral axis (R=G=B)
- have the same hue as the chosen white point. Near the black point,
- red, green or blue can only be added, not subtracted from zero, so
- the process of making the near black colors have the desired hue,
- will <span style="font-weight: bold;">lighten</span> them to some
- extent. For a device with a good contrast ratio or a black point
- that has nearly the same hue as the white, this should not affect
- the contrast ratio too severely. If the device contrast ratio is not
- so good, and the native black hue is noticeably different to that of
- the chosen white point (which is often the case for <span
- style="font-weight: bold;">LCD</span> type displays, or <span
- style="font-weight: bold;">CRT</span> type displays with one
- channel which has a poor level of black), this could have a
- noticeably detrimental effect on an already limited contrast ratio,
- and result in a black that is not as good as it can be, and a lower
- <span style="font-weight: bold;">-k</span> factor should be used. <span
- style="font-weight: bold;">-k</span> values can range between 0.0
- (no correction of black) to 1.0 (full correction of black). If less
- than full correction is chosen, then the resulting calibration
- curves will have the target white point down most of the curve, but
- will then blend over to the native or compromise black point that is
- blacker, but not of the right hue. The rate of this blend can be
- controlled with the <span style="font-weight: bold;">-A</span>
- parameter (see below). For applications where maximum contrast ratio
- is important (such as <b>Video</b>), use <b>-k0</b>. <br>
- <br>
+
+ explained above, the gamma value provided to the <span
+ style="font-weight: bold;">-g</span> option is used to set and
+ actual response curve that makes an allowance for the non-zero black
+ of the actual display, and will have the same relative output at 50%
+ input as the ideal gamma power curve, and so best matches typical
+ expectations. The <span style="font-weight: bold;">-G</span> option
+ is an alternative that allows the <span style="font-weight: bold;">actual</span>
+ power to be specified instead, meaning that when combined with the
+ displays non-zero black value, the response at 50% input will
+ probably not match that of the ideal power curve with that gamma
+ value.<br>
+ <br>
+ <a name="f"></a><span style="font-weight: bold;">-f [degree]</span>:
+ As explained in for the <span style="font-weight: bold;">-g</span>
+ and <span style="font-weight: bold;">-G</span> options, real
+ displays do not have a zero black response, while all the target
+ response curves do, so this has to be allowed for in some way. The
+ default way of handling this (equivalent to -f 1.0)&nbsp; is to
+ allow for this at the output of the ideal response curve, by
+ offsetting and scaling the output values.<span style="font-weight:
+ bold;"></span> This defined a curve that will match the responses
+ that many other systems provide and may be a better match to the
+ natural response of the display, but will give a less visually even
+ response from black<span style="font-weight: bold;"></span>. The
+ other alternative is to offset and scale the input values into the
+ ideal response curve so that zero input gives the actual non-zero
+ display response. This ensures the most visually even progression
+ from display minimum, but might be hard to achieve since it is
+ different to the naturally response of a display. A subtlety is to
+ provide a split between how much of the offset is accounted for as
+ input to the ideal response curve, and how much is accounted for at
+ the output, and this can be done by providing a parameter <span
+ style="font-weight: bold;">-f degree</span>, where the degree is
+ 0.0 accounts for it all as input offset, and 1.0 accounts for all of
+ it as output offset. If <span style="font-weight: bold;">-f</span>
+ is used without a specified degree, a degree of 0.0 is assumed, the
+ opposite of the default. <span style="font-weight: bold;">Note</span>
+ that using all input offset (degree == 0.0) is equivalent to the use
+ of the <span style="font-weight: bold;">BT.1886</span> transfer
+ function.<br>
+ <br>
+ <a name="a"></a><span style="font-weight: bold;">-a ambient</span>:
+ As explained for the <span style="font-weight: bold;">-g</span>
+ parameter, often colors are encoded in a situation with viewing
+ conditions that are quite different to the viewing conditions of a
+ typical display, with the expectation that this difference in
+ viewing conditions will be allowed for in the way the display is
+ calibrated. The <span style="font-weight: bold;">-a</span> option
+ is a way of doing this. By default <span style="font-weight: bold;">dispcal</span>
+ will not make any allowances for viewing conditions, but will
+ calibrate to the specified response curve, but if the <span
+ style="font-weight: bold;">-a</span> option is used, or the
+ ambient level is measured during the interactive display controls
+ portion of the calibration, an appropriate viewing conditions
+ adjustment will be performed. For a gamma value or sRGB, the
+ original viewing conditions will be assumed to be that of the sRGB
+ standard viewing conditions, while for REC 709 and SMPTE 240M they
+ will be assumed to be television studio viewing conditions. By
+ specifying or measuring the ambient lighting for your display, a
+ viewing conditions adjustment based on the CIECAM02 color appearance
+ model will be made for the brightness of&nbsp; your display and the
+ contrast it makes with your ambient light levels. <br>
+ <br>
+ <a name="k"></a><span style="font-weight: bold;">-k factor</span>:
+ Normally this will be set automatically, based on the measured black
+ level of the display. A <span style="font-weight: bold;">-k</span>
+ factor of 1.0 will make all colors down the neutral axis (R=G=B)
+ have the same hue as the chosen white point. Near the black point,
+ red, green or blue can only be added, not subtracted from zero, so
+ the process of making the near black colors have the desired hue,
+ will <span style="font-weight: bold;">lighten</span> them to some
+ extent. For a device with a good contrast ratio or a black point
+ that has nearly the same hue as the white, this should not affect
+ the contrast ratio too severely. If the device contrast ratio is not
+ so good, and the native black hue is noticeably different to that of
+ the chosen white point (which is often the case for <span
+ style="font-weight: bold;">LCD</span> type displays, or <span
+ style="font-weight: bold;">CRT</span> type displays with one
+ channel which has a poor level of black), this could have a
+ noticeably detrimental effect on an already limited contrast ratio,
+ and result in a black that is not as good as it can be, and a lower
+ <span style="font-weight: bold;">-k</span> factor should be used. <span
+ style="font-weight: bold;">-k</span> values can range between 0.0
+ (no correction of black) to 1.0 (full correction of black). If less
+ than full correction is chosen, then the resulting calibration
+ curves will have the target white point down most of the curve, but
+ will then blend over to the native or compromise black point that is
+ blacker, but not of the right hue. The rate of this blend can be
+ controlled with the <span style="font-weight: bold;">-A</span>
+ parameter (see below). For applications where maximum contrast ratio
+ is important (such as <b>Video</b>), use <b>-k0</b>. <br>
+ <br>
<a name="A"></a><span style="font-weight: bold;">-A rate</span>:&nbsp;
If
@@ -3018,641 +3018,641 @@ If
-
- the black point is not being set completely to the same hue as the
- white point (ie. because the <span style="font-weight: bold;">-k</span>
- factor is less than 1.0), then the resulting calibration curves will
- have the target white point down most of the curve, but will then
- blend over to the native or compromise black point that is blacker,
- but not of the right hue. The rate of this blend can be controlled
- with the <span style="font-weight: bold;">-A</span> parameter. The
- default value 4.0, which results in a target that switches from the
- white point target to the black, moderately close to the black
- point. While this typically gives a good visual result with the
- target neutral hue being maintained to the point where the crossover
- to the black hue is not visible, it may be asking too much of some
- displays (typically LCD type displays), and there may be some visual
- effects due to inconsistent color with viewing angle. For this
- situation a smaller value may give a better visual result (e.g. try
- values of 3.0 or 2.0. A value of 1.0 will set a pure linear blend
- from white point to black point). If there is too much coloration
- near black, try a larger value, e.g. 6.0 or 8.0.<br>
- <br>
- <a name="bhack"></a>The <b>-b</b> flag forces source 0,0,0 to map
- to destination 0,0,0. This may be useful with displays that have a
- very dark black point, and with an instrument is unable to measure
- it precisely, and where it is known in some other way that the
- display is <u>very well behaved</u> from black (i.e. that it has no
- "dead zone" above zero device input). Using this option with a
- display that is <u>not</u> well behaved, may result in a loss of
- shadow detail. This will override any <b>-k</b> factor.<br>
- <br>
- <a name="B"></a><span style="font-weight: bold;">-B</span>&nbsp; Set
- the target brightness of black in cd/m^2 (i.e. the absolute Y
- value). Setting too high a value may give strange results as it
- interacts with trying to achieve the target "advertised" gamma curve
- shape. You could try using -f 1 if this causes a problem.<br>
- <br>
- <a name="e"></a><span style="font-weight: bold;">-e [n]</span> Run <span
- style="font-weight: bold;">n</span> verify passes on the final
- curves. This is an extra set of instrument readings, that can be
- used to estimate how well the device will match the targets with the
- computed calibration curves. Note that the usefulness of the
- verification is sometimes limited by the repeatability of the device
- &amp; instrument readings. This is often evident for CRT displays,
- which (due to their refresh rate) flicker. More than one
- verification pass can be done by providing the parameter <span
- style="font-weight: bold;">n</span>, and by then comparing the
- successive verifications, some idea of the repeatability can be
- ascertained. The verification uses a fixed number of semi-random
- test values to test the calibration.<br>
- <br>
- <a name="z"></a><span style="font-weight: bold;">-z</span> Run
- verify pass on the display as it is currently setup (currently
- installed LUT curves). This will use the usual input parameters to
- establish the expected (target) characteristic. <span
- style="font-weight: bold;">Note</span> that if the initial
- calibration was modified due to it being out of gamut of the
- display, verify will show the resulting discrepancy. You can use <a
- href="dispwin.html">dispwin</a> to load a <span
- style="font-weight: bold;">.cal</span> file into the display
- before running dispcal <span style="font-weight: bold;">-z</span>.
- Note that if you set an Ambient light level interactively during the
- calibration, you need to enter the same number that was measured and
- set using the <span style="font-weight: bold;">-a</span> parameter
- for verify.<br>
- <br>
- <a name="P"></a> The <span style="font-weight: bold;">-P</span>
- parameter allows you to position and size the test patch window. By
- default it is places in the center of the screen, and sized
- appropriately for the type of instrument, or 10% of the width of the
- display if the display size is unknown.. The <span
- style="font-weight: bold;">ho</span> and <span
- style="font-weight: bold;">vo</span> values govern the horizontal
- and vertical offset respectively. A value of 0.0 positions the
- window to the far left or top of the screen, a value of 0.5
- positions it in the center of the screen (the default), and 1.0
- positions it to the far right or bottom of the screen. If three
- parameters are provided, then the <span style="font-weight: bold;">ss</span>
- parameter is a scale factor for the test window size. A value of 0.5
- for instance, would produce a half sized window. A value of 2.0 will
- produce a double size window. If four parameters are provided, then
- the last two set independent horizontal and vertical scaling
- factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
- specified as a single string (no space between the numbers and the
- comma). For example, to create a double sized test window at the top
- right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
- . To create a window twice as wide as high: <span
- style="font-weight: bold;">-P 1,0,2,1</span>.<br>
- <br>
- <a name="F"></a> The <span style="font-weight: bold;">-F</span>
- flag causes the while screen behind the test window to be masked
- with black. This can aid black accuracy when measuring CRT displays
- or projectors.<br>
- <br>
- <a name="E"></a> The <span style="font-weight: bold;">-E</span>
- flag causes the display test values to be scaled to the Video RGB
- encoding range of (16-235)/255. This also modifies the resulting
- calibration curve behavior downstream of dispcal. If a calibration
- curve created using -E gets installed or converted to an ICC profile
- 'vcgt' tag in the process of creating a profile in dispcal or
- colprof, the incoming full range values will first have the
- calibration curve applied and then be scaled to the Video encoding
- range (16-235)/255.<br>
- <br>
- <a name="n"></a><span style="font-weight: bold;">-n</span> When
- running on a UNIX based system that used the X11 Windowing System, <b>dispcal</b>
- normally selects the override redirect so that the test window will
- appear above any other windows on the display. On some systems this
- can interfere with window manager operation, and the <b>-n</b>
- option turns this behaviour off.<br>
- <br>
- <a name="J"></a> The -<span style="font-weight: bold;">J</span>
- option runs through the black and sensor relative calibration
- routines for the Xrite DTP92 and DTP94 instruments, the black level
- calibration for the Eye-One Display 1, and a CRT frequency
- calibration for the Eye-One Display 2. For the black calibration the
- instrument should be placed on an opaque, black surface, and any
- stray light should be avoided by placing something opaque over the
- instrument. If a Spectrolino is being used, then a white and black
- calibration will always be performed before the instrument can be
- placed on the display, unless the <a href="dispcal.html#N">-N</a>
- flag is used. Generally it is not necessary to do a calibration
- every time an instrument is used, just now and again. There is also
- no point in doing&nbsp; a CRT frequency calibration, as this will be
- done automatically at the commencement of patch reading, and will be
- lost between runs.<br>
- <br>
- <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
- instrument that requires regular calibration will ask for
- calibration on initial start-up. Sometimes this can be awkward if
- the instrument is being mounted in some sort of measuring jig, or
- annoying if several sets of readings are being taken in quick
- succession. The -<span style="font-weight: bold;">N</span>
- suppresses this initial calibration if a valid and not timed out
- previous calibration is recorded in the instrument or on the host
- computer. It is advisable to only use this option on the second and
- subsequent measurements in a single session.<br>
- <br>
- <a name="H"></a> The -<span style="font-weight: bold;">H</span>
- option turns on high resolution spectral mode, if the instrument
- supports it, such as the Eye-One Pro. See <a
- href="instruments.html">Operation of particular instruments</a>
- for more details. This may give better accuracy for display
- measurements.<br>
- <br>
- <a name="X1"></a> The -<span style="font-weight: bold;">X <span
- style="font-style: italic;">file.ccmx</span></span> option reads
- a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
- from the given file, and applies it to the colorimeter instruments
- readings. This can improve a colorimeters accuracy for a particular
- type of display. A list of contributed <span style="font-weight:
- bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
- <br>
- <a name="X2"></a> The -<span style="font-weight: bold;">X <span
- style="font-style: italic;">file.ccss</span></span> option reads
- a <a href="File_Formats.html#.ccss">Colorimeter Calibration
- Spectral Sample</a> from the given file, and uses it to set the
- colorimeter instruments calibration. This will only work with
- colorimeters that rely on sensor spectral sensitivity calibration
- information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
- or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
- Spyder 5</span>).This can improve a colorimeters accuracy for a
- particular type of display.<br>
- <br>
- <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
- observer, and is used to compute PCS (Profile Connection Space)
- tristimulus values from spectral readings or using a colorimeter
- that has CCSS capability. The following choices are available:<br>
- <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
- observer. The default.<br>
- &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
- observer.<br>
- &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
- observer<br>
- &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
- observer<br>
- &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
- observer<br>
- &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
- observer that has been adjusted using a 3x3 matrix to better agree
- with the 1931 2 degree observer.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that if you select
- anything other than the default 1931 2 degree observer, that the Y
- values will not be cd/m^2, due to the Y curve not being the CIE 1924
- photopic V(&#955;) luminosity function.<br>
- <br>
- <a name="I"></a> The -<span style="font-weight: bold;">I <span
- style="font-style: italic;">b|w</span></span> options invoke
- instrument black level, and display white level compensation
- (respectively). Instrument black level drift compensation attempts
- to combat instrument black calibration drift by using a display
- black test patch as a reference. If an instrument is not
- acclimatised sufficiently to the measurement conditions, changes in
- temperature can affect the black readings. Display white level drift
- compensation attempts to combat changes in display brightness as it
- warms up by measuring a white patch every so often, and using it to
- normalise all the other readings. If just instrument black drift
- compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
- If just display white level compensation is needed, use <span
- style="font-weight: bold;">-Iw</span>. If both are needed, use <span
- style="font-weight: bold;">-Ibw</span> or <span
- style="font-weight: bold;">-Iwb</span>.<span style="font-weight:
- bold;"> </span><br>
- <br>
- <a name="YR"></a> The -<span style="font-weight: bold;">Y R:<i>rate</i></span>
- options overrides calibration of the instrument refresh rate. This
- may be useful if the instrument supports this function and the
- refresh rate cannot be accurately calibrated from the display
- itself.<br>
- <br>
- <a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
- option uses a non-adaptive integration time emission measurement
- mode, if the instrument supports it, such as the Eye-One Pro,
- ColorMunki, i1d3 and K10. By default an adaptive integration time
- measurement mode will be used for emission measurements, but some
- instruments support a fixed integration time mode that can be used
- with display devices. This may give faster measurement times, but
- may also give less accurate low level readings.<br>
- <br>
- <a name="Yp"></a> The -<span style="font-weight: bold;">Y p</span>
- option skips asking the user to place the instrument on the display.
- Normally a grey patch is displayed, and then the user is asked to
- confirm that the instrument is in place, so that readings can
- commence. This flag disables that check. This may be useful in
- automating certain operations.<br>
- <br>
- <a name="C"></a> The -<span style="font-weight: bold;">C</span> <span
- style="font-weight: bold;">"command" </span>option allows a
- method of relaying each test value to some other display than that
- on the system running dispcal (for instance, a photo frame, PDA
- screen etc.), by causing the given command to be invoked to the
- shell, with six arguments. The first three arguments are the RGB
- test color as integers in the range 0 to 255, the second three
- parameters are the RGB test color as floating point numbers in the
- range 0.0 to 1.0. The script or tool should relay the given color to
- the screen in some manner (e.g. by generating a raster file of the
- given color and sending it to the display being profiled), before
- returning. Note that a test window will also be created on the
- system running dispread.<br>
- <br>
- <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
- style="font-weight: bold;">"command" </span>option allows a
- method of gathering each test value from some external source, such
- as an instrument that is not directly supported by Argyll. The given
- command is involked to the shell, with six arguments. The first
- three arguments are the RGB test color as integers in the range 0 to
- 255, the second three parameters are the RGB test color as floating
- point numbers in the range 0.0 to 1.0. The script or tool should
- create a file called <span style="font-weight: bold;">"command.meas</span>"
- that contains the XYZ values for the given RGB (or measured from the
- test window) in cd/m^2 as three numbers separated by spaces, before
- returning. If the command returns a non-zero return value, dispcal
- will abort. Note that a test window will also be created on the
- system running dispcal.<br>
- <br>
- <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
- parameter overrides the default serial communications flow control
- setting. The value <span style="font-weight: bold;">n</span> turns
- all flow control off, <span style="font-weight: bold;">h</span>
- sets hardware handshaking, and <span style="font-weight: bold;">x</span>
- sets Xon/Xoff handshaking. This commend may be useful in workaround
- serial communications issues with some systems and cables. <br>
- <br>
- <a name="D"></a>The <b>-D</b> flag causes communications and other
- instrument diagnostics to be printed to stdout. A level can be set
- between 1 .. 9, that may give progressively more verbose
- information, depending on the instrument. This can be useful in
- tracking down why an instrument can't connect.<br>
- <br>
- <a name="p1"></a><span style="font-weight: bold;">inoutfile</span>
- The final parameter on the command line is the base filename for the
- <a href="cal_format.html">.cal</a> file and the optional ICC
- profile. Normally this will be created (or an existing file will be
- overwritten). If the <span style="font-weight: bold;">-u</span>
- flag is used, then these files will be updated. If a different ICC
- profile name needs to be specified, do so as an argument to the <span
- style="font-weight: bold;">-o</span> flag.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that on an X11 system,
- if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
- is set (ie. set it to "yes"), then the presence of the XRandR 1.2
- extension will be ignored, and other extensions such as Xinerama and
- XF86VidMode extension will be used. This may be a way to work around
- buggy XRandR 1.2 implementations.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h2><a name="Adjustment"></a>Discussion and guide to display control
- adjustment:</h2>
- <br>
- The adjustment of the display controls (brightness, contrast, R, G
- &amp; B channel controls etc.) is very dependent on the particular
- monitor. Different types and brands of monitors will have different
- controls, or controls that operate in different ways. Some displays
- have almost no user controls, and so you may well be best skipping
- display adjustment, and going straight to calibration.<br>
- <br>
- Almost all LCD displays lack a real <span style="font-weight:
- bold;">contrast</span> control. Those that do present such a
- control generally fake it by adjusting the video signal. For this
- reason it is usually best to set an LCD's <span style="font-weight:
- bold;">contrast</span> control at its neutral setting (ie. the
- setting at which it doesn't change the video signal). Unfortunately,
- it can be hard to know what this neutral setting is. On some
- displays it is 50%, others 75%. If the LCD display has a "reset to
- factory defaults" mode, then try using this first, as a way of
- setting the <span style="font-weight: bold;">contrast</span>
- control to neutral. The LCD <span style="font-weight: bold;">brightness</span>
- control generally adjusts the level of backlighting the display
- gets, which affects the maximum brightness, and also tends to raise
- or lower the black level in proportion, without changing the
- displays response curve shape or overall contrast ratio. If your LCD
- display has a <span style="font-weight: bold;">backlight</span>
- control as well as a <span style="font-weight: bold;">brightness</span>
- control, then the brightness control is also probably being faked,
- and you are probably better off setting it to it's neutral setting,
- and using the <span style="font-weight: bold;">backlight</span>
- control in place of <span style="font-weight: bold;">brightness</span>
- in the following adjustments.<br>
- <br>
- Some high end displays have the ability to mimic various standard
- colorspaces such as sRGB or AdobeRGB. You could choose to calibrate
- and profile the display in such an emulation mode, although you
- probably don't want to fight the emulations white point and gamma.
- To get the best out of such a display you really want to choose it's
- "Native Gamut" setting, whatever that is called. Note that some
- people have reported bad experiences in trying to use "6-axis custom
- controls" on displays such as the Dell U2410, so attempting to use
- such a mode should be approached with caution. Ideally such a mode
- should be used to give just the underlying native display response,
- but the settings to achieve this may be very difficult to determine,
- and/or it may not be possible, depending on how such a mode distorts
- the RGB signals.<br>
- <br>
- On CRT based displays, the <span style="font-weight: bold;">brightness</span>
- control generally adjusts the black level of the display (sometimes
- called the <span style="font-weight: bold;">offset</span>), and as
- a side effect, tends to change the maximum brightness too. A CRT <span
- style="font-weight: bold;">contrast</span> control generally
- adjusts the maximum brightness (sometimes called <span
- style="font-weight: bold;">gain</span>) without affecting the
- black level a great deal. On a CRT both the <span
- style="font-weight: bold;">brightness</span> and <span
- style="font-weight: bold;">contrast</span> controls will tend to
- affect the shape or gamma of the display response curve.<br>
- <br>
- Many displays have some sort of color temperature adjustment. This
- may be in the form of some pre-set color temperatures, or in the
- form of individual Red, Green and Blue channel gain adjustments.
- Some CRT displays also have R, G &amp; B channel offset adjustments
- that will affect the color temperatures near black, as well as
- affect the individual channels curve shape. The color temperature
- adjustment will generally affect the maximum brightness, and may
- also affect the black level and the shape of the display response
- curves.<br>
- <br>
- Some special (expensive) LCD displays may have a white point
- adjustment that changes the color of the backlight. If you do not
- have one of these types of LCD displays, then attempting to change
- the white point of the display (even if it appears to have a "<span
- style="font-weight: bold;">white point selection</span>" or <span
- style="font-weight: bold;">R/G/B</span> "<span style="font-weight:
- bold;">gain</span>" controls") may not be a good idea, as once
- again these controls are probably being faked by manipulating the
- signal levels. Even if you do manage to change the white point
- significantly, it may do things like change the mid tone color too
- dramatically, or create a display response that is hard to correct
- with calibration, or results in side effects such as quantization
- (banding) or other undesirable effects. You may have to try out
- various controls (and your aim points for the display calibration),
- to decide what is reasonable to attempt on an LCD display.<br>
- <br>
- Due to the variety of controls as well as the interaction between
- them, it can be an iterative process to arrive at a good monitor
- set-up, before proceeding on to calibrating and profiling a display.
- For this reason, <span style="font-weight: bold;">dispcal</span>
- offers a menu of adjustment modes, so that the user can
- interactively and iteratively adjust the display controls to meet
- the desired targets.<br>
- <br>
- &nbsp; 1) Black level (CRT: Brightness)<br>
- &nbsp; 2) White point (Color temperature, R,G,B, Gain/Contrast)<br>
- &nbsp; 3) White level (CRT: Gain/Contrast, LCD:
- Brightness/Backlight)<br>
- &nbsp; 4) Black point (R,G,B, Offset/Brightness)<br>
- &nbsp; 5) Check all<br>
- &nbsp; 6) Measure and set ambient for viewing condition adjustment<br>
- &nbsp; 7) Continue on to calibration<br>
- &nbsp; 8) Exit<br>
- <br>
- There are four basic adjustment modes. Normally one would proceed
- through them in the order above, then perhaps repeat the first
- adjustment, before checking the overall settings. The White point
- and White level modes operate slightly differently, depending on
- whether a white target point has been set using the <span
- style="font-weight: bold;">-t -T</span> or <span
- style="font-weight: bold;">-w</span> options, and on whether a
- brightness target has been set using the <span style="font-weight:
- bold;">-b</span> option.<br>
- <br>
- <br>
- The first mode lets you adjust the black level of a CRT display.
- Given the current white level, it calculates a value that should
- produce a 1% display brightness if the black level is set correctly.
- After doing some initial measurements, it will show the target
- brightness value (in cd/m^2) on one line, and then underneath it
- will show continuously updated readings from the display. The left
- most character will switch from '\' to '/' or back again each time a
- reading is updated. Some instruments can be quite slow in measuring
- dark colors, and it's best to wait for a reading update before
- changing the controls more than once. Underneath the target value is
- displayed the current reading, and to the right of this is a '+',
- '-' or '=' symbol, which gives a hint as to which way to adjust the
- brightness control to improve the match to the target.<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">&nbsp; Adjust CRT brightness to get target level.
- Press space when done.</span><br style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp; Target
- 0.60</span><br style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; / Current 0.68&nbsp;
- -</span></small><br>
- <br>
- Once happy with the adjustment, press space to go back to the menu.<br>
- <br>
- <br>
- The second mode lets you adjust the color of the white point of the
- display. If a target white point has been set, it will show the
- target brightness value (in cd/m^2) on one line, together with the
- target chromaticity co-ordinates for the white point, and then
- underneath it will show continuously updated readings from the
- display. The left most character will switch from '\' to '/' or back
- again each time a reading is updated. Underneath the target
- brightness value is displayed the current reading, and then the
- current chromaticity co-ordinate values. To the right of this is the
- current delta E of the white point from the target, and further to
- the right are hints '+', '-' or '='&nbsp; as to which direction to
- adjust the individual Red, Green and Blue gain settings to move the
- white point in the direction of the target, and reduce the delta E.
- If the symbol is doubled, then this channel will have the greatest
- effect. If you do not have individual channel gain controls, then
- try choosing amongst color temperature pre-sets, to find one with
- the lowest delta E. Depending on the stability of the display, the
- coarseness of the controls, and the repeatability of the instrument,
- you may not be able to get a perfectly zero delta E.<br>
- <br>
- &nbsp;&nbsp; <small style="font-weight: bold;"><span
- style="font-family: monospace;">Adjust R,G &amp; B gain to get
- target x,y. Press space when done.<br>
- &nbsp;&nbsp; &nbsp; Target B 60.00, x 0.3451, y 0.3516<br>
- &nbsp; / Current B 60.05, x 0.3426, y 0.3506&nbsp; DE&nbsp;
- 1.4&nbsp; R+&nbsp; G+&nbsp; B--</span><span style="font-family:
- monospace;"></span></small><br>
- <br>
- If you did not set a white point target, then the information shown
- is a little different - it will show the initial white point value,
- as well as the color temperature, and the CIEDE2000 of the white
- point to either the Daylight or Black Body locus (depending on
- whether the <span style="font-weight: bold;">-T</span> flag was
- set). The constantly updated values show the same thing, and the
- Red, Green and Blue control hints show the direction to adjust the
- controls to place the white point on the locus. The control that
- will have the most direct effect on the color temperature will be
- the Blue, while the Green will most directly move the white point
- towards or away from the locus, thereby reducing the delta E of the
- white point to the locus (but there is interaction).<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">Adjust R,G &amp; B gain to desired white point.
- Press space when done.</span><br style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Initial B 47.25, x
- 0.3417, y 0.3456, CDT 5113 DE&nbsp; 6.9</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">\ Current B 47.38, x 0.3420,
- y 0.3460&nbsp; CDT 5104 DE&nbsp; 6.7&nbsp; R-- G+&nbsp; B-</span></small><br>
- <br>
- &nbsp;The brightness value is just there as a guide to what effect
- the adjustment is having on the overall brightness. Usually the
- white level brightness is adjusted using the next adjustment mode.
- Once happy with the adjustment, press space to go back to the menu.<br>
- <br>
- <br>
- The third mode lets you adjust the brightness of white on the
- display. If you set a target brightness using the <span
- style="font-weight: bold;"><span style="font-weight: bold;">-b</span></span>
- parameter, it will show the target brightness value (in cd/m^2) on
- one line, and then underneath it will show continuously updated
- readings from the display. The left most character will switch from
- '\' to '/' or back again each time a reading is updated. Underneath
- the target value is displayed the current reading, and to the right
- of this is a '+', '-' or '=' symbol, which gives a hint as to which
- way to adjust the CRT contrast or LCD brightness control to improve
- the match to the target.<br>
- <br>
- &nbsp;&nbsp; <small style="font-weight: bold;"><span
- style="font-family: monospace;">Adjust CRT Contrast or LCD
- Brightness to get target level. Press space when done.<br>
- &nbsp;&nbsp; &nbsp; Target 60.00<br>
- &nbsp; / Current 59.96&nbsp; +</span><span style="font-family:
- monospace;"></span></small><br>
- <br>
- If you did not set a brightness target, it will show the initial
- brightness as the target, and the current brightness, which you can
- then set any way you want:<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">Adjust CRT Contrast or LCD Brightness to desired
- level. Press space when done.</span><br style="font-family:
- monospace;">
- <span style="font-family: monospace;">&nbsp; Initial 47.32</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">/ Current 47.54</span></small><br>
- <br>
- Once happy with the adjustment, press space to go back to the menu.<br>
- <br>
- <br>
- The fourth mode lets you adjust the color of the black point of the
- display, if the display has Red, Green and Blue channel offset
- controls. It will show the target 1% brightness value (in cd/m^2) on
- one line, together with the target chromaticity co-ordinates for the
- black point, and then underneath it will show continuously updated
- readings from the display. The left most character will switch from
- '\' to '/' or back again each time a reading is updated. Underneath
- the target brightness value is displayed the current reading, and
- then the current chromaticity co-ordinate values. To the right of
- this is the current delta E of the black point from the target, and
- further to the right are hints '+', '-' or '='&nbsp; as to which
- direction to adjust the individual Red, Green and Blue offset
- settings to move the black point in the right direction. If the
- symbol is doubled, then this channel will have the greatest effect.
- <br>
- <br>
- <span style="font-family: monospace;"><span style="font-weight:
- bold;">&nbsp; Adjust R,G &amp; B offsets to get target x,y.
- Press space when done.<br>
- &nbsp;&nbsp; &nbsp; Target B 0.60, x 0.3451, y 0.3516<br>
- &nbsp; \ Current B 0.62, x 0.2782, y 0.2331&nbsp; DE&nbsp;
- 10.3&nbsp; R+&nbsp; G++ B-</span></span><small
- style="font-weight: bold;"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></small><br>
- <br>
- The 1%&nbsp; brightness value is just there as a guide to what
- effect the adjustment is having on the 1% brightness level. The
- combined channel offsets may have an effect on this in combination
- with the CRT brightness control. Press space to go back to the menu.<br>
- <br>
- <br>
- The fifth selection checks on the overall settings.&nbsp; If targets
- have been set, it will be like:<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">&nbsp; Target Brightness = 50.00, Current = 47.44,
- error = -5.1%<br>
- &nbsp; Target 50% Level&nbsp; = 10.32, Current =&nbsp; 8.10,
- error = -4.4%<br>
- &nbsp; Target Near Black =&nbsp; 0.47, Current =&nbsp; 0.68,
- error =&nbsp; 0.4%<br>
- &nbsp; Target white = x 0.3458, y 0.3586, Current = x 0.3420, y
- 0.3454, error =&nbsp; 7.55 DE<br>
- &nbsp; Target black = x 0.3458, y 0.3586, Current = x 0.2908, y
- 0.2270, error = 29.69 DE</span><span style="font-family:
- monospace;"></span></small><br>
- <br>
- or if no targets are set:<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">&nbsp; Current Brightness = 46.28</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Target 50%
- Level&nbsp; = 10.07, Current =&nbsp; 7.52, error = -5.5%</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Target Near Black
- =&nbsp; 0.46, Current =&nbsp; 0.46, error = -0.0%</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Current white = x
- 0.3439, y 0.3466, VCT 5098K DE&nbsp; 3.0</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Target black = x
- 0.3439, y 0.3466, Current = x 0.3093, y 0.2165, error = 30.30 DE</span></small><br>
- <br>
- and will then go back to the menu.<br>
- <br>
- The sixth selection <span style="font-weight: bold;">6)</span>
- allows the reading of you ambient lighting conditions if your
- instrument supports such a mode. Doing so will enable the <span
- style="font-weight: bold;">-a</span> option to compensate for your
- viewing conditions in the subsequent calibration. See <a
- href="dispcal.html#a">-a</a>.<br>
- <br>
- Once&nbsp; you're happy with the display set-up, you can either
- proceed on to the rest of the calibration by selecting <span
- style="font-weight: bold;">7)</span>, or exit and re-start by
- selecting <span style="font-weight: bold;">8)</span>. You might
- want to re-start if you want to change the calibration targets.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h2>Other caveats:</h2>
- NOTE that some <span style="font-weight: bold;">LCD</span> screens
- behave a little strangely near their absolute white point, and may
- therefore exhibit odd behavior at values just below white. It may be
- advisable in such cases to set a brightness slightly less than the
- maximum such a display is capable of.<br>
- <br>
- The program attempts to stop any screensaver or powersaver from
- interfering with the measurements, but this may not be effective on
- some systems, so it may be necessary to manually disable the
- screensaver and/or powersaver before commencing the calibration with
- a large number of patches.<br>
- <br>
- The calibration tables produced maintain the maximum level of
- precision available on a system. If the display has VideoLUTs
- available (Video Lookup Tables that the frame buffer values pass
- through on their way to the display) and thier outputs are better
- than 8 bits per component, then the resulting curves can reflect
- this, although few current operating systems and/or display cards
- actually support better than 8 bit per component output.<br>
- <br>
- If calibration curves are created for a display in which VideoLUTs
- are not available, then the resulting calibration file will be
- marked to indicate this, and a subsequent profile created with the
- calibration will not have the calibration converted to the 'vcgt'
- tag, since such a tag can't be loaded into the displays VideoLUTs.<br>
- <br>
- If communications break down with a USB connected instrument, you
- may have to unplug it, and plug it in again to recover operation.<br>
- <br>
- Some systems (Apple OS X in particular) have a special set of user
- interface controls ("Universal Access") that allows altering the
- display in ways designed to assist visually impaired users, by
- increasing contrast etc. This will interfere badly with any attempts
- to calibrate or profile such a system, and must be turned off in
- order to do so. Note that certain magic keyboard sequences can turn
- this on by accident.<br>
- <br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ the black point is not being set completely to the same hue as the
+ white point (ie. because the <span style="font-weight: bold;">-k</span>
+ factor is less than 1.0), then the resulting calibration curves will
+ have the target white point down most of the curve, but will then
+ blend over to the native or compromise black point that is blacker,
+ but not of the right hue. The rate of this blend can be controlled
+ with the <span style="font-weight: bold;">-A</span> parameter. The
+ default value 4.0, which results in a target that switches from the
+ white point target to the black, moderately close to the black
+ point. While this typically gives a good visual result with the
+ target neutral hue being maintained to the point where the crossover
+ to the black hue is not visible, it may be asking too much of some
+ displays (typically LCD type displays), and there may be some visual
+ effects due to inconsistent color with viewing angle. For this
+ situation a smaller value may give a better visual result (e.g. try
+ values of 3.0 or 2.0. A value of 1.0 will set a pure linear blend
+ from white point to black point). If there is too much coloration
+ near black, try a larger value, e.g. 6.0 or 8.0.<br>
+ <br>
+ <a name="bhack"></a>The <b>-b</b> flag forces source 0,0,0 to map
+ to destination 0,0,0. This may be useful with displays that have a
+ very dark black point, and with an instrument is unable to measure
+ it precisely, and where it is known in some other way that the
+ display is <u>very well behaved</u> from black (i.e. that it has no
+ "dead zone" above zero device input). Using this option with a
+ display that is <u>not</u> well behaved, may result in a loss of
+ shadow detail. This will override any <b>-k</b> factor.<br>
+ <br>
+ <a name="B"></a><span style="font-weight: bold;">-B</span>&nbsp; Set
+ the target brightness of black in cd/m^2 (i.e. the absolute Y
+ value). Setting too high a value may give strange results as it
+ interacts with trying to achieve the target "advertised" gamma curve
+ shape. You could try using -f 1 if this causes a problem.<br>
+ <br>
+ <a name="e"></a><span style="font-weight: bold;">-e [n]</span> Run <span
+ style="font-weight: bold;">n</span> verify passes on the final
+ curves. This is an extra set of instrument readings, that can be
+ used to estimate how well the device will match the targets with the
+ computed calibration curves. Note that the usefulness of the
+ verification is sometimes limited by the repeatability of the device
+ &amp; instrument readings. This is often evident for CRT displays,
+ which (due to their refresh rate) flicker. More than one
+ verification pass can be done by providing the parameter <span
+ style="font-weight: bold;">n</span>, and by then comparing the
+ successive verifications, some idea of the repeatability can be
+ ascertained. The verification uses a fixed number of semi-random
+ test values to test the calibration.<br>
+ <br>
+ <a name="z"></a><span style="font-weight: bold;">-z</span> Run
+ verify pass on the display as it is currently setup (currently
+ installed LUT curves). This will use the usual input parameters to
+ establish the expected (target) characteristic. <span
+ style="font-weight: bold;">Note</span> that if the initial
+ calibration was modified due to it being out of gamut of the
+ display, verify will show the resulting discrepancy. You can use <a
+ href="dispwin.html">dispwin</a> to load a <span
+ style="font-weight: bold;">.cal</span> file into the display
+ before running dispcal <span style="font-weight: bold;">-z</span>.
+ Note that if you set an Ambient light level interactively during the
+ calibration, you need to enter the same number that was measured and
+ set using the <span style="font-weight: bold;">-a</span> parameter
+ for verify.<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument, or 10% of the width of the
+ display if the display size is unknown.. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="E"></a> The <span style="font-weight: bold;">-E</span>
+ flag causes the display test values to be scaled to the Video RGB
+ encoding range of (16-235)/255. This also modifies the resulting
+ calibration curve behavior downstream of dispcal. If a calibration
+ curve created using -E gets installed or converted to an ICC profile
+ 'vcgt' tag in the process of creating a profile in dispcal or
+ colprof, the incoming full range values will first have the
+ calibration curve applied and then be scaled to the Video encoding
+ range (16-235)/255.<br>
+ <br>
+ <a name="n"></a><span style="font-weight: bold;">-n</span> When
+ running on a UNIX based system that used the X11 Windowing System, <b>dispcal</b>
+ normally selects the override redirect so that the test window will
+ appear above any other windows on the display. On some systems this
+ can interfere with window manager operation, and the <b>-n</b>
+ option turns this behaviour off.<br>
+ <br>
+ <a name="J"></a> The -<span style="font-weight: bold;">J</span>
+ option runs through the black and sensor relative calibration
+ routines for the Xrite DTP92 and DTP94 instruments, the black level
+ calibration for the Eye-One Display 1, and a CRT frequency
+ calibration for the Eye-One Display 2. For the black calibration the
+ instrument should be placed on an opaque, black surface, and any
+ stray light should be avoided by placing something opaque over the
+ instrument. If a Spectrolino is being used, then a white and black
+ calibration will always be performed before the instrument can be
+ placed on the display, unless the <a href="dispcal.html#N">-N</a>
+ flag is used. Generally it is not necessary to do a calibration
+ every time an instrument is used, just now and again. There is also
+ no point in doing&nbsp; a CRT frequency calibration, as this will be
+ done automatically at the commencement of patch reading, and will be
+ lost between runs.<br>
+ <br>
+ <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it, such as the Eye-One Pro. See <a
+ href="instruments.html">Operation of particular instruments</a>
+ for more details. This may give better accuracy for display
+ measurements.<br>
+ <br>
+ <a name="X1"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccmx</span></span> option reads
+ a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
+ from the given file, and applies it to the colorimeter instruments
+ readings. This can improve a colorimeters accuracy for a particular
+ type of display. A list of contributed <span style="font-weight:
+ bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
+ <br>
+ <a name="X2"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccss</span></span> option reads
+ a <a href="File_Formats.html#.ccss">Colorimeter Calibration
+ Spectral Sample</a> from the given file, and uses it to set the
+ colorimeter instruments calibration. This will only work with
+ colorimeters that rely on sensor spectral sensitivity calibration
+ information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
+ or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
+ Spyder 5</span>).This can improve a colorimeters accuracy for a
+ particular type of display.<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values from spectral readings or using a colorimeter
+ that has CCSS capability. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
+ observer that has been adjusted using a 3x3 matrix to better agree
+ with the 1931 2 degree observer.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you select
+ anything other than the default 1931 2 degree observer, that the Y
+ values will not be cd/m^2, due to the Y curve not being the CIE 1924
+ photopic V(&#955;) luminosity function.<br>
+ <br>
+ <a name="I"></a> The -<span style="font-weight: bold;">I <span
+ style="font-style: italic;">b|w</span></span> options invoke
+ instrument black level, and display white level compensation
+ (respectively). Instrument black level drift compensation attempts
+ to combat instrument black calibration drift by using a display
+ black test patch as a reference. If an instrument is not
+ acclimatised sufficiently to the measurement conditions, changes in
+ temperature can affect the black readings. Display white level drift
+ compensation attempts to combat changes in display brightness as it
+ warms up by measuring a white patch every so often, and using it to
+ normalise all the other readings. If just instrument black drift
+ compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
+ If just display white level compensation is needed, use <span
+ style="font-weight: bold;">-Iw</span>. If both are needed, use <span
+ style="font-weight: bold;">-Ibw</span> or <span
+ style="font-weight: bold;">-Iwb</span>.<span style="font-weight:
+ bold;"> </span><br>
+ <br>
+ <a name="YR"></a> The -<span style="font-weight: bold;">Y R:<i>rate</i></span>
+ options overrides calibration of the instrument refresh rate. This
+ may be useful if the instrument supports this function and the
+ refresh rate cannot be accurately calibrated from the display
+ itself.<br>
+ <br>
+ <a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
+ option uses a non-adaptive integration time emission measurement
+ mode, if the instrument supports it, such as the Eye-One Pro,
+ ColorMunki, i1d3 and K10. By default an adaptive integration time
+ measurement mode will be used for emission measurements, but some
+ instruments support a fixed integration time mode that can be used
+ with display devices. This may give faster measurement times, but
+ may also give less accurate low level readings.<br>
+ <br>
+ <a name="Yp"></a> The -<span style="font-weight: bold;">Y p</span>
+ option skips asking the user to place the instrument on the display.
+ Normally a grey patch is displayed, and then the user is asked to
+ confirm that the instrument is in place, so that readings can
+ commence. This flag disables that check. This may be useful in
+ automating certain operations.<br>
+ <br>
+ <a name="C"></a> The -<span style="font-weight: bold;">C</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of relaying each test value to some other display than that
+ on the system running dispcal (for instance, a photo frame, PDA
+ screen etc.), by causing the given command to be invoked to the
+ shell, with six arguments. The first three arguments are the RGB
+ test color as integers in the range 0 to 255, the second three
+ parameters are the RGB test color as floating point numbers in the
+ range 0.0 to 1.0. The script or tool should relay the given color to
+ the screen in some manner (e.g. by generating a raster file of the
+ given color and sending it to the display being profiled), before
+ returning. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of gathering each test value from some external source, such
+ as an instrument that is not directly supported by Argyll. The given
+ command is involked to the shell, with six arguments. The first
+ three arguments are the RGB test color as integers in the range 0 to
+ 255, the second three parameters are the RGB test color as floating
+ point numbers in the range 0.0 to 1.0. The script or tool should
+ create a file called <span style="font-weight: bold;">"command.meas</span>"
+ that contains the XYZ values for the given RGB (or measured from the
+ test window) in cd/m^2 as three numbers separated by spaces, before
+ returning. If the command returns a non-zero return value, dispcal
+ will abort. Note that a test window will also be created on the
+ system running dispcal.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="p1"></a><span style="font-weight: bold;">inoutfile</span>
+ The final parameter on the command line is the base filename for the
+ <a href="cal_format.html">.cal</a> file and the optional ICC
+ profile. Normally this will be created (or an existing file will be
+ overwritten). If the <span style="font-weight: bold;">-u</span>
+ flag is used, then these files will be updated. If a different ICC
+ profile name needs to be specified, do so as an argument to the <span
+ style="font-weight: bold;">-o</span> flag.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h2><a name="Adjustment"></a>Discussion and guide to display control
+ adjustment:</h2>
+ <br>
+ The adjustment of the display controls (brightness, contrast, R, G
+ &amp; B channel controls etc.) is very dependent on the particular
+ monitor. Different types and brands of monitors will have different
+ controls, or controls that operate in different ways. Some displays
+ have almost no user controls, and so you may well be best skipping
+ display adjustment, and going straight to calibration.<br>
+ <br>
+ Almost all LCD displays lack a real <span style="font-weight:
+ bold;">contrast</span> control. Those that do present such a
+ control generally fake it by adjusting the video signal. For this
+ reason it is usually best to set an LCD's <span style="font-weight:
+ bold;">contrast</span> control at its neutral setting (ie. the
+ setting at which it doesn't change the video signal). Unfortunately,
+ it can be hard to know what this neutral setting is. On some
+ displays it is 50%, others 75%. If the LCD display has a "reset to
+ factory defaults" mode, then try using this first, as a way of
+ setting the <span style="font-weight: bold;">contrast</span>
+ control to neutral. The LCD <span style="font-weight: bold;">brightness</span>
+ control generally adjusts the level of backlighting the display
+ gets, which affects the maximum brightness, and also tends to raise
+ or lower the black level in proportion, without changing the
+ displays response curve shape or overall contrast ratio. If your LCD
+ display has a <span style="font-weight: bold;">backlight</span>
+ control as well as a <span style="font-weight: bold;">brightness</span>
+ control, then the brightness control is also probably being faked,
+ and you are probably better off setting it to it's neutral setting,
+ and using the <span style="font-weight: bold;">backlight</span>
+ control in place of <span style="font-weight: bold;">brightness</span>
+ in the following adjustments.<br>
+ <br>
+ Some high end displays have the ability to mimic various standard
+ colorspaces such as sRGB or AdobeRGB. You could choose to calibrate
+ and profile the display in such an emulation mode, although you
+ probably don't want to fight the emulations white point and gamma.
+ To get the best out of such a display you really want to choose it's
+ "Native Gamut" setting, whatever that is called. Note that some
+ people have reported bad experiences in trying to use "6-axis custom
+ controls" on displays such as the Dell U2410, so attempting to use
+ such a mode should be approached with caution. Ideally such a mode
+ should be used to give just the underlying native display response,
+ but the settings to achieve this may be very difficult to determine,
+ and/or it may not be possible, depending on how such a mode distorts
+ the RGB signals.<br>
+ <br>
+ On CRT based displays, the <span style="font-weight: bold;">brightness</span>
+ control generally adjusts the black level of the display (sometimes
+ called the <span style="font-weight: bold;">offset</span>), and as
+ a side effect, tends to change the maximum brightness too. A CRT <span
+ style="font-weight: bold;">contrast</span> control generally
+ adjusts the maximum brightness (sometimes called <span
+ style="font-weight: bold;">gain</span>) without affecting the
+ black level a great deal. On a CRT both the <span
+ style="font-weight: bold;">brightness</span> and <span
+ style="font-weight: bold;">contrast</span> controls will tend to
+ affect the shape or gamma of the display response curve.<br>
+ <br>
+ Many displays have some sort of color temperature adjustment. This
+ may be in the form of some pre-set color temperatures, or in the
+ form of individual Red, Green and Blue channel gain adjustments.
+ Some CRT displays also have R, G &amp; B channel offset adjustments
+ that will affect the color temperatures near black, as well as
+ affect the individual channels curve shape. The color temperature
+ adjustment will generally affect the maximum brightness, and may
+ also affect the black level and the shape of the display response
+ curves.<br>
+ <br>
+ Some special (expensive) LCD displays may have a white point
+ adjustment that changes the color of the backlight. If you do not
+ have one of these types of LCD displays, then attempting to change
+ the white point of the display (even if it appears to have a "<span
+ style="font-weight: bold;">white point selection</span>" or <span
+ style="font-weight: bold;">R/G/B</span> "<span style="font-weight:
+ bold;">gain</span>" controls") may not be a good idea, as once
+ again these controls are probably being faked by manipulating the
+ signal levels. Even if you do manage to change the white point
+ significantly, it may do things like change the mid tone color too
+ dramatically, or create a display response that is hard to correct
+ with calibration, or results in side effects such as quantization
+ (banding) or other undesirable effects. You may have to try out
+ various controls (and your aim points for the display calibration),
+ to decide what is reasonable to attempt on an LCD display.<br>
+ <br>
+ Due to the variety of controls as well as the interaction between
+ them, it can be an iterative process to arrive at a good monitor
+ set-up, before proceeding on to calibrating and profiling a display.
+ For this reason, <span style="font-weight: bold;">dispcal</span>
+ offers a menu of adjustment modes, so that the user can
+ interactively and iteratively adjust the display controls to meet
+ the desired targets.<br>
+ <br>
+ &nbsp; 1) Black level (CRT: Brightness)<br>
+ &nbsp; 2) White point (Color temperature, R,G,B, Gain/Contrast)<br>
+ &nbsp; 3) White level (CRT: Gain/Contrast, LCD:
+ Brightness/Backlight)<br>
+ &nbsp; 4) Black point (R,G,B, Offset/Brightness)<br>
+ &nbsp; 5) Check all<br>
+ &nbsp; 6) Measure and set ambient for viewing condition adjustment<br>
+ &nbsp; 7) Continue on to calibration<br>
+ &nbsp; 8) Exit<br>
+ <br>
+ There are four basic adjustment modes. Normally one would proceed
+ through them in the order above, then perhaps repeat the first
+ adjustment, before checking the overall settings. The White point
+ and White level modes operate slightly differently, depending on
+ whether a white target point has been set using the <span
+ style="font-weight: bold;">-t -T</span> or <span
+ style="font-weight: bold;">-w</span> options, and on whether a
+ brightness target has been set using the <span style="font-weight:
+ bold;">-b</span> option.<br>
+ <br>
+ <br>
+ The first mode lets you adjust the black level of a CRT display.
+ Given the current white level, it calculates a value that should
+ produce a 1% display brightness if the black level is set correctly.
+ After doing some initial measurements, it will show the target
+ brightness value (in cd/m^2) on one line, and then underneath it
+ will show continuously updated readings from the display. The left
+ most character will switch from '\' to '/' or back again each time a
+ reading is updated. Some instruments can be quite slow in measuring
+ dark colors, and it's best to wait for a reading update before
+ changing the controls more than once. Underneath the target value is
+ displayed the current reading, and to the right of this is a '+',
+ '-' or '=' symbol, which gives a hint as to which way to adjust the
+ brightness control to improve the match to the target.<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Adjust CRT brightness to get target level.
+ Press space when done.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp; Target
+ 0.60</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; / Current 0.68&nbsp;
+ -</span></small><br>
+ <br>
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The second mode lets you adjust the color of the white point of the
+ display. If a target white point has been set, it will show the
+ target brightness value (in cd/m^2) on one line, together with the
+ target chromaticity co-ordinates for the white point, and then
+ underneath it will show continuously updated readings from the
+ display. The left most character will switch from '\' to '/' or back
+ again each time a reading is updated. Underneath the target
+ brightness value is displayed the current reading, and then the
+ current chromaticity co-ordinate values. To the right of this is the
+ current delta E of the white point from the target, and further to
+ the right are hints '+', '-' or '='&nbsp; as to which direction to
+ adjust the individual Red, Green and Blue gain settings to move the
+ white point in the direction of the target, and reduce the delta E.
+ If the symbol is doubled, then this channel will have the greatest
+ effect. If you do not have individual channel gain controls, then
+ try choosing amongst color temperature pre-sets, to find one with
+ the lowest delta E. Depending on the stability of the display, the
+ coarseness of the controls, and the repeatability of the instrument,
+ you may not be able to get a perfectly zero delta E.<br>
+ <br>
+ &nbsp;&nbsp; <small style="font-weight: bold;"><span
+ style="font-family: monospace;">Adjust R,G &amp; B gain to get
+ target x,y. Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target B 60.00, x 0.3451, y 0.3516<br>
+ &nbsp; / Current B 60.05, x 0.3426, y 0.3506&nbsp; DE&nbsp;
+ 1.4&nbsp; R+&nbsp; G+&nbsp; B--</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ If you did not set a white point target, then the information shown
+ is a little different - it will show the initial white point value,
+ as well as the color temperature, and the CIEDE2000 of the white
+ point to either the Daylight or Black Body locus (depending on
+ whether the <span style="font-weight: bold;">-T</span> flag was
+ set). The constantly updated values show the same thing, and the
+ Red, Green and Blue control hints show the direction to adjust the
+ controls to place the white point on the locus. The control that
+ will have the most direct effect on the color temperature will be
+ the Blue, while the Green will most directly move the white point
+ towards or away from the locus, thereby reducing the delta E of the
+ white point to the locus (but there is interaction).<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">Adjust R,G &amp; B gain to desired white point.
+ Press space when done.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Initial B 47.25, x
+ 0.3417, y 0.3456, CDT 5113 DE&nbsp; 6.9</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">\ Current B 47.38, x 0.3420,
+ y 0.3460&nbsp; CDT 5104 DE&nbsp; 6.7&nbsp; R-- G+&nbsp; B-</span></small><br>
+ <br>
+ &nbsp;The brightness value is just there as a guide to what effect
+ the adjustment is having on the overall brightness. Usually the
+ white level brightness is adjusted using the next adjustment mode.
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The third mode lets you adjust the brightness of white on the
+ display. If you set a target brightness using the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">-b</span></span>
+ parameter, it will show the target brightness value (in cd/m^2) on
+ one line, and then underneath it will show continuously updated
+ readings from the display. The left most character will switch from
+ '\' to '/' or back again each time a reading is updated. Underneath
+ the target value is displayed the current reading, and to the right
+ of this is a '+', '-' or '=' symbol, which gives a hint as to which
+ way to adjust the CRT contrast or LCD brightness control to improve
+ the match to the target.<br>
+ <br>
+ &nbsp;&nbsp; <small style="font-weight: bold;"><span
+ style="font-family: monospace;">Adjust CRT Contrast or LCD
+ Brightness to get target level. Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target 60.00<br>
+ &nbsp; / Current 59.96&nbsp; +</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ If you did not set a brightness target, it will show the initial
+ brightness as the target, and the current brightness, which you can
+ then set any way you want:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">Adjust CRT Contrast or LCD Brightness to desired
+ level. Press space when done.</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp; Initial 47.32</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">/ Current 47.54</span></small><br>
+ <br>
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The fourth mode lets you adjust the color of the black point of the
+ display, if the display has Red, Green and Blue channel offset
+ controls. It will show the target 1% brightness value (in cd/m^2) on
+ one line, together with the target chromaticity co-ordinates for the
+ black point, and then underneath it will show continuously updated
+ readings from the display. The left most character will switch from
+ '\' to '/' or back again each time a reading is updated. Underneath
+ the target brightness value is displayed the current reading, and
+ then the current chromaticity co-ordinate values. To the right of
+ this is the current delta E of the black point from the target, and
+ further to the right are hints '+', '-' or '='&nbsp; as to which
+ direction to adjust the individual Red, Green and Blue offset
+ settings to move the black point in the right direction. If the
+ symbol is doubled, then this channel will have the greatest effect.
+ <br>
+ <br>
+ <span style="font-family: monospace;"><span style="font-weight:
+ bold;">&nbsp; Adjust R,G &amp; B offsets to get target x,y.
+ Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target B 0.60, x 0.3451, y 0.3516<br>
+ &nbsp; \ Current B 0.62, x 0.2782, y 0.2331&nbsp; DE&nbsp;
+ 10.3&nbsp; R+&nbsp; G++ B-</span></span><small
+ style="font-weight: bold;"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><br>
+ <br>
+ The 1%&nbsp; brightness value is just there as a guide to what
+ effect the adjustment is having on the 1% brightness level. The
+ combined channel offsets may have an effect on this in combination
+ with the CRT brightness control. Press space to go back to the menu.<br>
+ <br>
+ <br>
+ The fifth selection checks on the overall settings.&nbsp; If targets
+ have been set, it will be like:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Target Brightness = 50.00, Current = 47.44,
+ error = -5.1%<br>
+ &nbsp; Target 50% Level&nbsp; = 10.32, Current =&nbsp; 8.10,
+ error = -4.4%<br>
+ &nbsp; Target Near Black =&nbsp; 0.47, Current =&nbsp; 0.68,
+ error =&nbsp; 0.4%<br>
+ &nbsp; Target white = x 0.3458, y 0.3586, Current = x 0.3420, y
+ 0.3454, error =&nbsp; 7.55 DE<br>
+ &nbsp; Target black = x 0.3458, y 0.3586, Current = x 0.2908, y
+ 0.2270, error = 29.69 DE</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ or if no targets are set:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Current Brightness = 46.28</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target 50%
+ Level&nbsp; = 10.07, Current =&nbsp; 7.52, error = -5.5%</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target Near Black
+ =&nbsp; 0.46, Current =&nbsp; 0.46, error = -0.0%</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Current white = x
+ 0.3439, y 0.3466, VCT 5098K DE&nbsp; 3.0</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target black = x
+ 0.3439, y 0.3466, Current = x 0.3093, y 0.2165, error = 30.30 DE</span></small><br>
+ <br>
+ and will then go back to the menu.<br>
+ <br>
+ The sixth selection <span style="font-weight: bold;">6)</span>
+ allows the reading of you ambient lighting conditions if your
+ instrument supports such a mode. Doing so will enable the <span
+ style="font-weight: bold;">-a</span> option to compensate for your
+ viewing conditions in the subsequent calibration. See <a
+ href="dispcal.html#a">-a</a>.<br>
+ <br>
+ Once&nbsp; you're happy with the display set-up, you can either
+ proceed on to the rest of the calibration by selecting <span
+ style="font-weight: bold;">7)</span>, or exit and re-start by
+ selecting <span style="font-weight: bold;">8)</span>. You might
+ want to re-start if you want to change the calibration targets.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h2>Other caveats:</h2>
+ NOTE that some <span style="font-weight: bold;">LCD</span> screens
+ behave a little strangely near their absolute white point, and may
+ therefore exhibit odd behavior at values just below white. It may be
+ advisable in such cases to set a brightness slightly less than the
+ maximum such a display is capable of.<br>
+ <br>
+ The program attempts to stop any screensaver or powersaver from
+ interfering with the measurements, but this may not be effective on
+ some systems, so it may be necessary to manually disable the
+ screensaver and/or powersaver before commencing the calibration with
+ a large number of patches.<br>
+ <br>
+ The calibration tables produced maintain the maximum level of
+ precision available on a system. If the display has VideoLUTs
+ available (Video Lookup Tables that the frame buffer values pass
+ through on their way to the display) and thier outputs are better
+ than 8 bits per component, then the resulting curves can reflect
+ this, although few current operating systems and/or display cards
+ actually support better than 8 bit per component output.<br>
+ <br>
+ If calibration curves are created for a display in which VideoLUTs
+ are not available, then the resulting calibration file will be
+ marked to indicate this, and a subsequent profile created with the
+ calibration will not have the calibration converted to the 'vcgt'
+ tag, since such a tag can't be loaded into the displays VideoLUTs.<br>
+ <br>
+ If communications break down with a USB connected instrument, you
+ may have to unplug it, and plug it in again to recover operation.<br>
+ <br>
+ Some systems (Apple OS X in particular) have a special set of user
+ interface controls ("Universal Access") that allows altering the
+ display in ways designed to assist visually impaired users, by
+ increasing contrast etc. This will interfere badly with any attempts
+ to calibrate or profile such a system, and must be turned off in
+ order to do so. Note that certain magic keyboard sequences can turn
+ this on by accident.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/dispread.html b/doc/dispread.html
index 52a38c2..12077eb 100644
--- a/doc/dispread.html
+++ b/doc/dispread.html
@@ -1,25 +1,25 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>dispread</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- </head>
- <body>
- <h2><b>spectro/dispread</b>&nbsp;</h2>
- <h3>Summary</h3>
- Display test patches on a monitor, read the colorimetric value
- result with the colorimeter, and create the chart readings file. The
- type of instrument is determined by the communication port selected.
- Emission and display measurement instruments are supported.<br>
- <br>
- If you want to read a display manually rather than automatically,
- see <a href="chartread.html">chartread</a> and the <a
- href="chartread.html#d">-d</a> option.<br>
- <h3>Usage</h3>
- <small style="font-family: monospace;">dispread [-options]<i>
- inoutfile</i><br>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispread</b>&nbsp;</h2>
+ <h3>Summary</h3>
+ Display test patches on a monitor, read the colorimetric value
+ result with the colorimeter, and create the chart readings file. The
+ type of instrument is determined by the communication port selected.
+ Emission and display measurement instruments are supported.<br>
+ <br>
+ If you want to read a display manually rather than automatically,
+ see <a href="chartread.html">chartread</a> and the <a
+ href="chartread.html#d">-d</a> option.<br>
+ <h3>Usage</h3>
+ <small style="font-family: monospace;">dispread [-options]<i>
+ inoutfile</i><br>
&nbsp;<a href="#v">-v</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -54,17 +54,17 @@
-
- &nbsp;&nbsp;&nbsp;&nbsp; Verbose mode<br>
- &nbsp;</small><font size="-1"><a style="font-family: monospace;"
- href="#display">-display displayname</a><span
- style="font-family: monospace;"> [X11 only] Choose X11 display
- name<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- [X11 only]Choose the display from the following list (default
- 1),<br>
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Verbose mode<br>
+ &nbsp;</small><font size="-1"><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [X11 only] Choose X11 display
+ name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [X11 only]Choose the display from the following list (default
+ 1),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
and
optionally
@@ -106,9 +106,9 @@ m
-
- for VideoLUT access.</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ for VideoLUT access.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Choose
the
@@ -150,8 +150,8 @@ list
-
- (default 1)</span></font><small style="font-family: monospace;"><br>
+
+ (default 1)</span></font><small style="font-family: monospace;"><br>
</small><span style="font-family: monospace;">&nbsp;<a href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -188,9 +188,9 @@ list
-
- Display via a web server at port (default 8080)</span><br>
- <span style="font-family: monospace;">&nbsp;<a href="#dmadvr">-dmadvr</a>
+
+ Display via a web server at port (default 8080)</span><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#dmadvr">-dmadvr</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -214,22 +214,22 @@ list
-
- [MSWin] Display via MadVR Video Renderer</span><br>
+
+ [MSWin] Display via MadVR Video Renderer</span><br>
<tt>&nbsp;</tt><tt><a href="#dcc">-dcc[:n]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- </tt><tt>Display via n'th ChromeCast (default 1, ? for list)</tt><br>
- <small style="font-family: monospace;"> <span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#c">-c listno</a><span style="font-family: monospace;">
- &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set
- communication port from the following list (default 1)<br>
- </span></small><font size="-1"><span style="font-family:
+
+ </tt><tt>Display via n'th ChromeCast (default 1, ? for list)</tt><br>
+ <small style="font-family: monospace;"> <span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#c">-c listno</a><span style="font-family: monospace;">
+ &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set
+ communication port from the following list (default 1)<br>
+ </span></small><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#p">-p</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -264,10 +264,10 @@ list
-
- Use telephoto mode (ie. for a projector) (if available)</span></font><br>
- &nbsp; <font size="-1"><span style="font-family: monospace;"><a
- href="#y">-y X</a>
+
+ Use telephoto mode (ie. for a projector) (if available)</span></font><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#y">-y X</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Display
@@ -304,10 +304,10 @@ Display
-
- type - instrument specific list to choose from.</span></font><br>
- <small style="font-family: monospace;">&nbsp;<span
- style="text-decoration: underline;">-</span><a href="#k">k
+
+ type - instrument specific list to choose from.</span></font><br>
+ <small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;">-</span><a href="#k">k
file.cal</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -342,10 +342,10 @@ Display
-
- Load calibration file into display while reading<br>
- </small><small style="font-family: monospace;">&nbsp;<span
- style="text-decoration: underline;">-</span><a href="#K">K
+
+ Load calibration file into display while reading<br>
+ </small><small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;">-</span><a href="#K">K
file.cal</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Apply
@@ -381,8 +381,8 @@ Apply
-
- calibration file to test values while reading</small><br>
+
+ calibration file to test values while reading</small><br>
<tt>&nbsp;<a href="#V">-V</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -398,8 +398,8 @@ Apply
-
- [MSWin] Enable MadVR color management (3dLut)</tt><br>
+
+ [MSWin] Enable MadVR color management (3dLut)</tt><br>
<small style="font-family: monospace;">&nbsp;<a href="#s">-s</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -434,12 +434,12 @@ Apply
-
- &nbsp;&nbsp;&nbsp;&nbsp; Save spectral information (default don't
- save)<br>
- </small><font style="font-family: monospace;" size="-1">&nbsp;<a
- href="#P">-P ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position
- test window and scale it<br>
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Save spectral information (default don't
+ save)<br>
+ </small><font style="font-family: monospace;" size="-1">&nbsp;<a
+ href="#P">-P ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position
+ test window and scale it<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ho,vi:
0.0
@@ -481,8 +481,8 @@ center,
-
- 1.0 = right/bottom etc.<br>
+
+ 1.0 = right/bottom etc.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ss:
0.5
@@ -524,8 +524,8 @@ normal,
-
- 2.0 = double etc.<br>
+
+ 2.0 = double etc.<br>
</font><font size="-1"><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -553,10 +553,10 @@ normal,
-
- ss,vs: = optional horizontal, vertical scale.</span></font><br>
- <font style="font-family: monospace;" size="-1"> &nbsp;</font><font
- size="-1"><span style="font-family: monospace;"><a href="#F">-F</a>
+
+ ss,vs: = optional horizontal, vertical scale.</span></font><br>
+ <font style="font-family: monospace;" size="-1"> &nbsp;</font><font
+ size="-1"><span style="font-family: monospace;"><a href="#F">-F</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -591,10 +591,10 @@ normal,
-
- Fill whole screen with black background</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
- size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
+
+ Fill whole screen with black background</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
+ size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -614,11 +614,11 @@ normal,
-
- </span></font><small><span style="font-family: monospace;">Video
- encode output as (16-235)/255 "TV" levels</span></small><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
- size="-1"><span style="font-family: monospace;"><a href="#Z">-Z
+
+ </span></font><small><span style="font-family: monospace;">Video
+ encode output as (16-235)/255 "TV" levels</span></small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
+ size="-1"><span style="font-family: monospace;"><a href="#Z">-Z
nbits</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -638,7 +638,7 @@ normal,
-
+
</span></font><small><span style="font-family: monospace;">Quantize
test
values
@@ -658,9 +658,9 @@ fit
-
- in nbits</span></small><br style="font-family: monospace;">
- <small style="font-family: monospace;">&nbsp;<span
+
+ in nbits</span></small><br style="font-family: monospace;">
+ <small style="font-family: monospace;">&nbsp;<span
style="text-decoration: underline;"></span><a href="#n">-n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
[X11
@@ -702,9 +702,9 @@ redirect
-
- on test window<br>
- </small><small style="font-family: monospace;">&nbsp;<a href="#J">-J</a>
+
+ on test window<br>
+ </small><small style="font-family: monospace;">&nbsp;<a href="#J">-J</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -739,9 +739,9 @@ redirect
-
- &nbsp;&nbsp;&nbsp;&nbsp; Run calibration first</small><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Run calibration first</small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -776,17 +776,17 @@ redirect
-
- Disable initial calibration of instrument if possible<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#H">-H</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
- available)</span></font><font size="-1"><span
- style="font-family: monospace;"></span><span style="font-family:
- monospace;"><br>
- &nbsp;<a href="#w">-w</a>
+
+ Disable initial calibration of instrument if possible<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#H">-H</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
+ available)</span></font><font size="-1"><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ &nbsp;<a href="#w">-w</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Disable
normalisation
@@ -828,9 +828,9 @@ Y
-
- 100</span></font><small><span style="font-family: monospace;"></span></small><br>
- &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+
+ 100</span></font><small><span style="font-family: monospace;"></span></small><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -865,9 +865,9 @@ Y
-
- Apply Colorimeter Correction Matrix</span></font><br>
- <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
+
+ Apply Colorimeter Correction Matrix</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Use
Colorimeter
@@ -905,14 +905,14 @@ Calibration
-
- Spectral Samples for calibration</span><font size="-1"><span
- style="font-family: monospace;"><br>
- </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
- style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
- colorimeter data:</span><br style="font-family: monospace;">
+
+ Spectral Samples for calibration</span><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
+ colorimeter data:</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -947,12 +947,12 @@ Calibration
-
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
- style="font-family: monospace;">(def.)</span></small><small><span
- style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
- J&amp;V 1978_2, 1964_10c</span></small><br>
- <small><span style="font-family: monospace;">&nbsp;<a
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
+ style="font-family: monospace;">(def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2, 1964_10c</span></small><br>
+ <small><span style="font-family: monospace;">&nbsp;<a
href="dispread.html#I">-I b|w</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Drift
compensation,
@@ -994,8 +994,8 @@ Both:
-
- -Ibw</span></small><br>
+
+ -Ibw</span></small><br>
<small><span style="font-family: monospace;"><tt>&nbsp;<a href="#YR">-Y
@@ -1008,7 +1008,7 @@ Both:
-
+
R:<i>rate</i></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1021,12 +1021,12 @@ Both:
-
- Override measured refresh rate with rate Hz<br>
- </tt>&nbsp;</span></small><font size="-1"><span
- style="font-family: monospace;"></span><a style=" font-family:
- monospace;" href="#YA">-<font size="-1">Y</font> A</a><span
- style="font-family: monospace;">
+
+ Override measured refresh rate with rate Hz<br>
+ </tt>&nbsp;</span></small><font size="-1"><span
+ style="font-family: monospace;"></span><a style=" font-family:
+ monospace;" href="#YA">-<font size="-1">Y</font> A</a><span
+ style="font-family: monospace;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1052,31 +1052,31 @@ Both:
-
- Use non-adaptive integration time mode (if available).</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style=" font-family: monospace;" href="#Yp">-<font size="-1">Y</font>
- <font size="-1">p</font></a><span style="font-family:
- monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; Don't wait for the instrument to be placed on
- the display</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#C">-C "command"</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
- "command" each time a color is set<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#M">-M "command"</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
- "command" each time a color is measured</span></font><br>
- <small>&nbsp; <a style="font-family: monospace;" href="#x">-x x</a><span
+
+ Use non-adaptive integration time mode (if available).</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#Yp">-<font size="-1">Y</font>
+ <font size="-1">p</font></a><span style="font-family:
+ monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Don't wait for the instrument to be placed on
+ the display</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#C">-C "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is set<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#M">-M "command"</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is measured</span></font><br>
+ <small>&nbsp; <a style="font-family: monospace;" href="#x">-x x</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Take
- manually entered
- XYZ values</span></small><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+Take
+ manually entered
+ XYZ values</span></small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
serial
@@ -1118,11 +1118,11 @@ n
-
- none, h = HW, x = Xon/Xoff</span></font><br>
- <small style="font-family: monospace;">&nbsp;<a href="#D">-D [level]</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Print debug
- diagnostics to stderr</small><br>
+
+ none, h = HW, x = Xon/Xoff</span></font><br>
+ <small style="font-family: monospace;">&nbsp;<a href="#D">-D [level]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Print debug
+ diagnostics to stderr</small><br>
<small style="font-family: monospace;">&nbsp;<a href="#p1"><i>inoutfile</i></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1157,73 +1157,73 @@ n
-
- Base name for input[<a href="File_Formats.html#.ti1">.ti1</a>]/output[<a
- href="File_Formats.html#.ti3">.ti3</a>] file.<br>
- </small> <br>
- <b>Examples</b><br>
- <br>
- dispread -c1 -i92 mycrt<br>
- <h3>Comments<br>
- </h3>
- This is the tool for exercising a display, in order to measure its
- color characteristics. The device test colors are defined by the
- outfile.ti1 file, while the resulting device+colorimetric and
- optional spectral readings are stored in the outfile.ti3 file.
- Display calibration curves can be applied during the measurements,
- and the curves included in the resulting .ti3 data file using the <span
- style="font-weight: bold;">-k</span>flag. See <a
- href="dispcal.html">dispcal</a> for information on how&nbsp; to
- calibrate the display before profiling it. For best results, you
- should run this against a neutral grey desktop background, and avoid
- having any bright images or windows on the screen at the time you
- run it.<br>
- <br>
- <a name="v"></a> The <b>-v</b> flag reports progress information.<br>
- <br>
- <a name="display"></a><span style="font-weight: bold;">-display</span>:
- When running on a UNIX based system that used the X11 Windowing
- System, <b>dispread</b> will by default use the $DISPLAY
- environment variable to determine which display and screen to read
- from. This can be overridden by supplying an X11 display name to the
- <span style="font-weight: bold;">-display</span> option. Note that
- if Xinerama is active, you can't select the screen using $DISPLAY or
- -display, you have to select it using the <span style="font-weight:
- bold;">-d</span> parameter.<br>
- <br>
- <a name="d"></a> <span style="font-weight: bold;">-d</span>: By
- default the main display will be the location of the test window. If
- the system has more than one display or screen, an alternate
- display/screen can be selected with the <span style="font-weight:
- bold;">-d</span> parameter. If you invoke <span
- style="font-weight: bold;">dispread</span> so as to display the
- usage information (i.e. "dispread -?" or "dispread --"), then the
- discovered displays/screens will be listed. Multiple displays may
- not be listed, if they appear as a single display to the operating
- system (ie. the multi-display support is hidden in the video card
- driver). On UNIX based system that used the X11 Windowing System,
- the <span style="font-weight: bold;">-d</span> parameter will
- override the screen specified by the $DISPLAY or <span
- style="font-weight: bold;">-display</span> parameter.<br>
- <br>
- On X11 the inability to access VideoLUTs could be because you are
- trying to access a remote display, and the remote display doesn't
- support the XF86VidMode extension, or perhaps you are running
- multiple monitors using NVidia TwinView, or MergedFB, and trying to
- access anything other than the primary monitor. TwinView and
- MergedFB don't properly support the XF86VidMode extension for
- multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
- to test whether the VideoLUTs are accessible for a particular
- display. See also below, on how to select a different display for
- VideoLUT access. Also note that dispcal will fail if the Visual
- depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
- 256 entries per color component, so the Visual generally needs to be
- 24 bits, 8 bits per color component.<br>
- <br>
- <a name="dnm"></a>Because of the difficulty cause by TwinView and
- MergedFB in X11 based systems, you can optionally specify a separate
- display number after the display that is going to be used to present
- test patches, for accessing the VideoLUT hardware. This must be
+
+ Base name for input[<a href="File_Formats.html#.ti1">.ti1</a>]/output[<a
+ href="File_Formats.html#.ti3">.ti3</a>] file.<br>
+ </small> <br>
+ <b>Examples</b><br>
+ <br>
+ dispread -c1 -i92 mycrt<br>
+ <h3>Comments<br>
+ </h3>
+ This is the tool for exercising a display, in order to measure its
+ color characteristics. The device test colors are defined by the
+ outfile.ti1 file, while the resulting device+colorimetric and
+ optional spectral readings are stored in the outfile.ti3 file.
+ Display calibration curves can be applied during the measurements,
+ and the curves included in the resulting .ti3 data file using the <span
+ style="font-weight: bold;">-k</span>flag. See <a
+ href="dispcal.html">dispcal</a> for information on how&nbsp; to
+ calibrate the display before profiling it. For best results, you
+ should run this against a neutral grey desktop background, and avoid
+ having any bright images or windows on the screen at the time you
+ run it.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag reports progress information.<br>
+ <br>
+ <a name="display"></a><span style="font-weight: bold;">-display</span>:
+ When running on a UNIX based system that used the X11 Windowing
+ System, <b>dispread</b> will by default use the $DISPLAY
+ environment variable to determine which display and screen to read
+ from. This can be overridden by supplying an X11 display name to the
+ <span style="font-weight: bold;">-display</span> option. Note that
+ if Xinerama is active, you can't select the screen using $DISPLAY or
+ -display, you have to select it using the <span style="font-weight:
+ bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a> <span style="font-weight: bold;">-d</span>: By
+ default the main display will be the location of the test window. If
+ the system has more than one display or screen, an alternate
+ display/screen can be selected with the <span style="font-weight:
+ bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispread</span> so as to display the
+ usage information (i.e. "dispread -?" or "dispread --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed, if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or <span
+ style="font-weight: bold;">-display</span> parameter.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
+ <a name="dnm"></a>Because of the difficulty cause by TwinView and
+ MergedFB in X11 based systems, you can optionally specify a separate
+ display number after the display that is going to be used to present
+ test patches, for accessing the VideoLUT hardware. This must be
specified as a single string, e.g. <span style="font-weight: bold;">-d
@@ -1258,423 +1258,423 @@ n
-
- 1,2</span> . Some experimentation may be needed using <a
- href="dispwin.html">dispwin</a> on such systems, to discover what
- screen has access to the VideoLUT hardware, and which screens the
- test patches appear on. You may be able to calibrate one screen, and
- then share the calibration with another screen. Profiling can be
- done independently to calibration.<br>
- <br>
- <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
- <span style="font-weight: bold;">-dweb:port</span> starts a
- standalone web server on your machine, which then allows a local or
- remote web browser to display the the color test patches. By default
- port <span style="font-weight: bold;">8080</span> is used, but this
- can be overridden by appending a <span style="font-weight: bold;">:</span>
- and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
- The URL will be <span style="font-weight: bold;">http://</span>
- then name of the machine or its I.P. address followed by a colon and
- the port number - e.g something like <span style="font-weight:
- bold;">http://192.168.0.1:8080</span>. If you use the verbose
- option (<span style="font-weight: bold;">-v</span>) then a likely
- URL will be printed once the server is started, or you could run <span
- style="font-weight: bold;">ipconfig</span> (MSWin) or <span
- style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
- and identify an internet address for your machine that way. <b>
- JavaScript</b> needs to be enabled in your web browser for this to
- work. You may have to modify any firewall to permit port 8080 to be
- accessed on your machine.<br>
- <br>
- Note that if you use this method of displaying test patches, that
- there is no access to the display VideoLUTs and that the colors will
- be displayed with 8 bit per component precision, and any
- screen-saver or power-saver will not be disabled. You will also be
- at the mercy of any color management applied by the web browser, and
- may have to carefully review and configure such color management.
- See the <a href="dispcal.html#o">-o</a> flag for an explanation of
- the implications of having no access to the VideoLUTs.<br>
- <br>
- <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
- [MSWin only] causes test patches to be displayed using the MadVR
- video renderer. Note that will have to start <b>MadTPG</b> before
- running dispread, and that while you can adjust the "Test Pattern
- Configuration" controls, you should <u>not</u> normally alter the
- "Existing Calibration" controls, as dispread will set these
- appropriately. See also <tt><a
- href="dispread.html#V">-V</a> flag.</tt><br>
- <br>
- <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
- causes test patches to be displayed using and available <a
- href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
- your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
- local network. Note that the ChromeCast as a test patch source is
- probably the<b> least accurate</b> of your choices, since it
- up-samples the test patch and transforms from RGB to YCC and back,
- but should be accurate within ± 1 bit. You may have to modify any
- firewall to permit port 8081 to be accessed on your machine if it
+
+ 1,2</span> . Some experimentation may be needed using <a
+ href="dispwin.html">dispwin</a> on such systems, to discover what
+ screen has access to the VideoLUT hardware, and which screens the
+ test patches appear on. You may be able to calibrate one screen, and
+ then share the calibration with another screen. Profiling can be
+ done independently to calibration.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:port</span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way. <b>
+ JavaScript</b> needs to be enabled in your web browser for this to
+ work. You may have to modify any firewall to permit port 8080 to be
+ accessed on your machine.<br>
+ <br>
+ Note that if you use this method of displaying test patches, that
+ there is no access to the display VideoLUTs and that the colors will
+ be displayed with 8 bit per component precision, and any
+ screen-saver or power-saver will not be disabled. You will also be
+ at the mercy of any color management applied by the web browser, and
+ may have to carefully review and configure such color management.
+ See the <a href="dispcal.html#o">-o</a> flag for an explanation of
+ the implications of having no access to the VideoLUTs.<br>
+ <br>
+ <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
+ [MSWin only] causes test patches to be displayed using the MadVR
+ video renderer. Note that will have to start <b>MadTPG</b> before
+ running dispread, and that while you can adjust the "Test Pattern
+ Configuration" controls, you should <u>not</u> normally alter the
+ "Existing Calibration" controls, as dispread will set these
+ appropriately. See also <tt><a
+ href="dispread.html#V">-V</a> flag.</tt><br>
+ <br>
+ <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
+ causes test patches to be displayed using and available <a
+ href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
+ your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
+ local network. Note that the ChromeCast as a test patch source is
+ probably the<b> least accurate</b> of your choices, since it
+ up-samples the test patch and transforms from RGB to YCC and back,
+ but should be accurate within ± 1 bit. You may have to modify any
+ firewall to permit port 8081 to be accessed on your machine if it
falls back to the Default receiver (see <a href="Installing.html">installation
-
- instructions</a> for your platform).<br>
- <br>
- <a name="c"></a> <span style="font-weight: bold;">-c</span>: The
- instrument is assumed to communicate through a USB or serial
- communication port, and the port can be selected with the <b>-c</b>
- option, if the instrument is not connected to the first port. If you
- invoke <span style="font-weight: bold;">dispread</span> so as to
- display the usage information (i.e. "dispread -?" or "dispread --"),
- then the discovered USB and serial ports will be listed. On
- UNIX/Linux, a list of all possible serial ports are shown, but not
- all of them may actually be present on your system.<br>
- <br>
- <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
- allows measuring in telephoto mode, using instruments that support
- this mode, e.g. the ColorMunki. Telephoto mode is one for taking
- emissive measurements from a distance (ie. telespectometer,
- tele-colorimeter) mode, and typically would be used for measuring
- projector type displays. If a device does not support a specific
- telephoto mode, then the normal emissive mode may be suitable for
- measuring projectors.<br>
- <br>
- <a name="y"></a>The <span style="font-weight: bold;">-y</span> flag
- allows setting the Display Type. The selection typically determines
- two aspects of of the instrument operation: <span
- style="font-weight: bold;">1)</span> It may set the measuring mode
- to suite <a
- href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
- style="font-weight: bold;">refresh</span> or <span
- style="font-weight: bold;">non-refresh</span> displays</a>.
- Typically only LCD (Liquid Crystal) displays have a non-refresh
- nature. <span style="font-weight: bold;">2)</span> It may select an
- instrument calibration matrix suitable for a particular display
- type. The selections available depends on the type and model of
- instrument, and a list of the options for the discovered instruments
- will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
- information. For more details on what particular instruments support
- and how this works, see <a href="instruments.html">Operation of
- particular instruments</a>. <b>3)</b> Any installed CCSS files
- (if applicable), or CCMX files. These files are typically created
- using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
- href="oeminst.html">oeminst</a>. The default and Base Calibration
- types will be indicated in the usage.<br>
- <br>
- <a name="s"></a><span style="font-weight: bold;">-s</span>: By
- default only the colorimetric information (XYZ value) will be saved,
- but for instruments that support spectral readings (such as the
- Gretag Spectrolino), the <b>-s</b> option will save the spectral
- readings to the .ti3 file as well.<br>
- <br>
- <a name="k"></a> <span style="font-weight: bold;">-k: </span>If a
- display video lookup table calibration <a
- href="File_Formats.html#.cal">.cal</a> file is provided, it will
- be loaded into the display <span style="font-weight: bold;">VideoLUTs</span>
- while the measurements are being taken, thereby being applied to the
- measurement values, and the calibration will also included in the
- resulting .ti3 data file, so that <a href="colprof.html">colprof</a>
- can include it as a <span style="font-weight: bold;">vcgt</span>
- tag in the resulting profile. This is the <span style="font-weight:
- bold;">normal</span> way to profile a calibrated display. The
- calibration file has usually been created using <a
- href="dispcal.html">dispcal</a>. If the calibration file indicates
- that the displays VideoLUTs are not accessible, or if they prove not
- to be accessible, then dispread will switch to <span
- style="font-weight: bold;">-K</span> mode (see below). If a
- calibration file is not supplied using <b>-k</b> or <b>-K</b>,
- then the display will be measured in whatever calibration state it
- is in, and no calibration information is saved to the resulting .ti3
- file.<br>
- If the calibration file provided created using video range encoding
- (dispcal -E), then the <b>-E</b> option in dispread will be
- triggered automatically.<br>
- <span style="font-weight: bold;">NOTE</span> that the calibration is
- loaded into the display hardware just before the instrument starts
- measurement, after the test window first appears.<br>
- <br>
- <a name="K"></a> <span style="font-weight: bold;">-K: </span>If a
- display video lookup table calibration <a
- href="File_Formats.html#.cal">.cal</a> file is provided, it will
- be applied to the test values for each measurement, and also
- included in the resulting .ti3 data file, so that <a
- href="colprof.html">colprof</a> can include it as a <span
- style="font-weight: bold;">vcgt</span> tag in the resulting
- profile. This is <span style="font-weight: bold;">NOT</span>
- normally the best way to profile a calibrated display, since the
- frame buffer may have lower precision than the VideoLUTs output
- values. This is the way calibration should be applied if MadVR is
- being used to display the test patches. If a calibration file is not
- supplied using <b>-k</b> or <b>-K</b>, then the display will be
- measured in whatever calibration state it is in, and no calibration
- information is saved to the resulting .ti3 file.<br>
- If the calibration file provided created using video range encoding
- (dispcal -E), then the <b>-E</b> option in dispread will be
- triggered automatically.<br>
- <br>
- <a name="V"></a><b>-V:</b> [MSWin] If using MadVR to display test
- patches, then enable Color Managenent (3dLut). This would be used
- for verification measurement.<br>
- <br>
- <a name="P"></a> The <span style="font-weight: bold;">-P</span>
- parameter allows you to position and size the test patch window. By
- default it is places in the center of the screen, and sized
- appropriately for the type of instrument, or 10% of the width of the
- display if the display size is unknown. The <span
- style="font-weight: bold;">ho</span> and <span
- style="font-weight: bold;">vo</span> values govern the horizontal
- and vertical offset respectively. A value of 0.0 positions the
- window to the far left or top of the screen, a value of 0.5
- positions it in the center of the screen (the default), and 1.0
- positions it to the far right or bottom of the screen. If three
- parameters are provided, then the <span style="font-weight: bold;">ss</span>
- parameter is a scale factor for the test window size. A value of 0.5
- for instance, would produce a half sized window. A value of 2.0 will
- produce a double size window. If four parameters are provided, then
- the last two set independent horizontal and vertical scaling
- factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
- specified as a single string (no space between the numbers and the
- comma). For example, to create a double sized test window at the top
- right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
- . To create a window twice as wide as high: <span
- style="font-weight: bold;">-P 1,0,2,1</span>.<br>
- <br>
- <a name="F"></a> The <span style="font-weight: bold;">-F</span>
- flag causes the while screen behind the test window to be masked
- with black. This can aid black accuracy when measuring CRT displays
- or projectors.<br>
- <br>
- <a name="E"></a> The <span style="font-weight: bold;">-E</span>
- flag causes the test values to be scaled to the Video RGB encoding
- range of 16/255 to 235/255. If the calibration file provided using
- the <b>-k</b> or <b>-K</b> flag was created using video range
- encoding, then this option will be triggered automatically. This
- will also set quantization of 8 bits (see -Z flag below). If your
- video connection is better than 8 bits (ie. 10 or 12 bits), then you
- may wish to raise this default.<br>
- <br>
- <a name="Z"></a> <b>-Z nbits </b>Normally the target device values
- are floating point numbers that may get rounded and quantized in the
- process of printing them or reproducing them on the display device.
- If some of this quantization can be accounted for, it may improve
- the accuracy of the resulting profile, and the <span
- style="font-weight: bold;">Q</span> parameter allows this
- quantization to be specified. The parameter is the number of binary
- digits (bits) that the device values should be quantized to. An idea
- of the number of bits of precision that makes its way to your
- display can be obtained by using <a href="dispcal.html#R">dispcal
- -R</a> If Video encoding is selected (see -E flag above), then 8
- bits is selected by default. On systems using an VGA connection or
- Display Port with a graphics card with VideoLUT entries with greater
- than 8 bits depth, or if using the MadVR rendered with dithering,
- then a higher bit depth is typically possible.<br>
- <br>
- <a name="n"></a><span style="font-weight: bold;">-n</span>: When
- running on a UNIX based system that used the X11 Windowing System, <b>dispread</b>
- normally selects the override redirect so that the test window will
- appear above any other windows on the display. On some systems this
- can interfere with window manager operation, and the <b>-n</b>
- option turns this behaviour off.<br>
- <br>
- <a name="J"></a> The -<span style="font-weight: bold;">J</span>
- option runs through the black and sensor relative calibration
- routines for the Xrite DTP92 and DTP94 instrument, the black level
- calibration for the Eye-One Display 1, and a CRT frequency
- calibration for the Eye-One Display 2. For the black calibration the
- instrument should be placed on an opaque, black surface, and any
- stray light should be avoided by placing something opaque over the
- instrument. If a Spectrolino is being used, then a white and black
- calibration will always be performed before the instrument can be
- placed on the display, unless the <a href="#N">-N</a> flag is used.
- Generally it is not necessary to do a calibration every time an
- instrument is used, just now and again. There is no point in
- doing&nbsp; a CRT frequency calibration, as this will be done
- automatically at the commencement of patch reading.<br>
- <br>
- <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
- instrument that requires regular calibration will ask for
- calibration on initial start-up. Sometimes this can be awkward if
- the instrument is being mounted in some sort of measuring jig, or
- annoying if several sets of readings are being taken in quick
- succession. The -<span style="font-weight: bold;">N</span>
- suppresses this initial calibration if a valid and not timed out
- previous calibration is recorded in the instrument or on the host
- computer. It is advisable to only use this option on the second and
- subsequent measurements in a single session.<br>
- <br>
- <a name="H"></a> The -<span style="font-weight: bold;">H</span>
- option turns on high resolution spectral mode, if the instrument
- supports it. See <a href="instruments.html">Operation of particular
- instruments</a> for more details. This may give better accuracy
- for display measurements.<br>
- <br>
- <a name="w"></a>The <b>-w</b> flag disables the normalisation of
- the white patch value to 100.0, resulting in values that are in
- cd/m^2. This is mainly for diagnostic purposes.<br>
- <br>
- <a name="X1"></a> The -<span style="font-weight: bold;">X <span
- style="font-style: italic;">file.ccmx</span></span> option reads
- a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
- from the given file, and applies it to the colorimeter instruments
- readings. This can improve a colorimeters accuracy for a particular
- type of display. A list of contributed <span style="font-weight:
- bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
- <br>
- <a name="X2"></a> The -<span style="font-weight: bold;">X <span
- style="font-style: italic;">file.ccss</span></span> option reads
- a <a href="File_Formats.html#.ccss">Colorimeter Calibration
- Spectral Sample</a> from the given file, and uses it to set the
- colorimeter instruments calibration. This will only work with
- colorimeters that rely on sensor spectral sensitivity calibration
- information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
- or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
- Spyder 5</span>).This can improve a colorimeters accuracy for a
- particular type of display.<br>
- <br>
- <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
- observer, and is used to compute PCS (Profile Connection Space)
- tristimulus values from spectral readings or using a colorimeter
- that has CCSS capability. The following choices are available:<br>
- <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
- observer. The default.<br>
- &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
- observer.<br>
- &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
- observer<br>
- &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
- observer<br>
- &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
- observer<br>
- &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
- observer that has been adjusted using a 3x3 matrix to better agree
- with the 1931 2 degree observer.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that if you select
- anything other than the default 1931 2 degree observer, that the Y
- values will not be cd/m^2, due to the Y curve not being the CIE 1924
- photopic V(&#955;) luminosity function.<br>
- <br>
- <a name="I"></a> The -<span style="font-weight: bold;">I <span
- style="font-style: italic;">b|w</span></span> options invoke
- instrument black level, and display white level compensation
- (respectively). Instrument black level drift compensation attempts
- to combat instrument black calibration drift by using a display
- black test patch as a reference. If an instrument is not
- acclimatised sufficiently to the measurement conditions, changes in
- temperature can affect the black readings. Display white level drift
- compensation attempts to combat changes in display brightness as it
- warms up by measuring a white patch every so often, and using it to
- normalise all the other readings. If just instrument black drift
- compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
- If just display white level compensation is needed, use <span
- style="font-weight: bold;">-Iw</span>. If both are needed, use <span
- style="font-weight: bold;">-Ibw</span> or <span
- style="font-weight: bold;">-Iwb</span>.<br>
- <br>
- <a name="YR"></a> The -<span style="font-weight: bold;">Y R:<i>rate</i></span>
- options overrides calibration of the instrument refresh rate. This
- may be useful if the instrument supports this function and the
- refresh rate cannot be accurately calibrated from the display
- itself.<br>
- <span style="font-weight: bold;">&nbsp;<br>
- </span><a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
- option uses a non-adaptive integration time emission measurement
- mode, if the instrument supports it, such as the Eye-One Pro,
- ColorMunki, i1d3 and K10. By default an adaptive integration time
- measurement mode will be used for emission measurements, but some
- instruments support a fixed integration time mode that can be used
- with display devices. This may give faster measurement times, but
- may also give less accurate low level readings.<br>
- <br>
- <a name="Yp"></a> The -<span style="font-weight: bold;">Y p</span>
- option skips asking the user to place the instrument on the display.
- Normally a grey patch is displayed, and then the user is asked to
- confirm that the instrument is in place, so that readings can
- commence. This flag disables that check. This may be useful in
- automating certain operations.<br>
- <span style="font-weight: bold;"><br>
- </span><a name="C"></a> The -<span style="font-weight: bold;">C</span>
- <span style="font-weight: bold;">"command" </span>option allows a
- method of relaying each test value to some other display than that
- on the system running dispread (for instance, a photo frame, PDA
- screen etc.), by causing the given command to be invoked to the
- shell, with six arguments. The first three arguments are the RGB
- test color as integers in the range 0 to 255, the second three
- parameters are the RGB test color as floating point numbers in the
- range 0.0 to 1.0. The script or tool should relay the given color to
- the screen in some manner (e.g. by generating a raster file of the
- given color and sending it to the display being profiled), before
- returning. Note that a test window will also be created on the
- system running dispread.<br>
- <br>
- <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
- style="font-weight: bold;">"command" </span>option allows a
- method of gathering each test value from some external source, such
- as an instrument that is not directly supported by Argyll. The given
- command is involked to the shell, with six arguments. The first
- three arguments are the RGB test color as integers in the range 0 to
- 255, the second three parameters are the RGB test color as floating
- point numbers in the range 0.0 to 1.0. The script or tool should
- create a file called <span style="font-weight: bold;">"command.meas</span>"
- that contains the XYZ values for the given RGB (or measured from the
- test window) in cd/m^2 as three numbers separated by spaces, before
- returning. If the command returns a non-zero return value, dispread
- will abort. Note that a test window will also be created on the
- system running dispread.<br>
- <br>
- <a name="x"></a> The <b>-x</b> flag causes dispread to expect
- values to be manually entered for each reading, rather than using an
- instrument to do the measurements.&nbsp; This mode is ideal if your
- instrument is not supported by Argyll. XYZ values should be entered.
- It is possible to navigate about the test values being measured, so
- as to do them in any order, as well as re-do values, in case of any
- mistakes.<br>
- <br>
- <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
- parameter overrides the default serial communications flow control
- setting. The value <span style="font-weight: bold;">n</span> turns
- all flow control off, <span style="font-weight: bold;">h</span>
- sets hardware handshaking, and <span style="font-weight: bold;">x</span>
- sets Xon/Xoff handshaking. This commend may be useful in workaround
- serial communications issues with some systems and cables. <br>
- <br>
- <a name="D"></a>The <b>-D</b> flag causes communications and other
- instrument diagnostics to be printed to stdout. A level can be set
- between 1 .. 9, that may give progressively more verbose
- information, depending on the instrument. This can be useful in
- tracking down why an instrument can't connect.<br>
- <br>
- <a name="p1"></a> The final parameter on the command line is the
- base filename for the <a href="File_Formats.html#.ti1">.ti1</a>
- input file, and the <a href="File_Formats.html#.ti3">.ti3</a>
- output file. <b>dispread</b> will add the .ti1 and .ti3 extensions
- automatically.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that on an X11 system,
- if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
- is set (ie. set it to "yes"), then the presence of the XRandR 1.2
- extension will be ignored, and other extensions such as Xinerama and
- XF86VidMode extension will be used. This may be a way to work around
- buggy XRandR 1.2 implementations.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- If a large number of patches is being read, the screensaver on many
- systems can interfere with the operation of dispread. It is
- therefore advisable in these cases to manually turn off the
- screensaver before commencing the measurements.<br>
- <br>
- If communications break down with a USB connected instrument, you
- may have to unplug it, and plug it in again to recover.<br>
- <br>
- Some systems (Apple OSX in particular) have a special set of user
- interface controls ("Universal Access") that allows altering the
- display in ways designed to assist visually impaired users, by
- increasing contrast etc. This will interfere badly with any attempts
- to calibrate or profile such a system, and must be turned off in
- order to do so. Note that certain magic keyboard sequences can turn
- this on by accident.<br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ instructions</a> for your platform).<br>
+ <br>
+ <a name="c"></a> <span style="font-weight: bold;">-c</span>: The
+ instrument is assumed to communicate through a USB or serial
+ communication port, and the port can be selected with the <b>-c</b>
+ option, if the instrument is not connected to the first port. If you
+ invoke <span style="font-weight: bold;">dispread</span> so as to
+ display the usage information (i.e. "dispread -?" or "dispread --"),
+ then the discovered USB and serial ports will be listed. On
+ UNIX/Linux, a list of all possible serial ports are shown, but not
+ all of them may actually be present on your system.<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ allows measuring in telephoto mode, using instruments that support
+ this mode, e.g. the ColorMunki. Telephoto mode is one for taking
+ emissive measurements from a distance (ie. telespectometer,
+ tele-colorimeter) mode, and typically would be used for measuring
+ projector type displays. If a device does not support a specific
+ telephoto mode, then the normal emissive mode may be suitable for
+ measuring projectors.<br>
+ <br>
+ <a name="y"></a>The <span style="font-weight: bold;">-y</span> flag
+ allows setting the Display Type. The selection typically determines
+ two aspects of of the instrument operation: <span
+ style="font-weight: bold;">1)</span> It may set the measuring mode
+ to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument calibration matrix suitable for a particular display
+ type. The selections available depends on the type and model of
+ instrument, and a list of the options for the discovered instruments
+ will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. <b>3)</b> Any installed CCSS files
+ (if applicable), or CCMX files. These files are typically created
+ using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
+ href="oeminst.html">oeminst</a>. The default and Base Calibration
+ types will be indicated in the usage.<br>
+ <br>
+ <a name="s"></a><span style="font-weight: bold;">-s</span>: By
+ default only the colorimetric information (XYZ value) will be saved,
+ but for instruments that support spectral readings (such as the
+ Gretag Spectrolino), the <b>-s</b> option will save the spectral
+ readings to the .ti3 file as well.<br>
+ <br>
+ <a name="k"></a> <span style="font-weight: bold;">-k: </span>If a
+ display video lookup table calibration <a
+ href="File_Formats.html#.cal">.cal</a> file is provided, it will
+ be loaded into the display <span style="font-weight: bold;">VideoLUTs</span>
+ while the measurements are being taken, thereby being applied to the
+ measurement values, and the calibration will also included in the
+ resulting .ti3 data file, so that <a href="colprof.html">colprof</a>
+ can include it as a <span style="font-weight: bold;">vcgt</span>
+ tag in the resulting profile. This is the <span style="font-weight:
+ bold;">normal</span> way to profile a calibrated display. The
+ calibration file has usually been created using <a
+ href="dispcal.html">dispcal</a>. If the calibration file indicates
+ that the displays VideoLUTs are not accessible, or if they prove not
+ to be accessible, then dispread will switch to <span
+ style="font-weight: bold;">-K</span> mode (see below). If a
+ calibration file is not supplied using <b>-k</b> or <b>-K</b>,
+ then the display will be measured in whatever calibration state it
+ is in, and no calibration information is saved to the resulting .ti3
+ file.<br>
+ If the calibration file provided created using video range encoding
+ (dispcal -E), then the <b>-E</b> option in dispread will be
+ triggered automatically.<br>
+ <span style="font-weight: bold;">NOTE</span> that the calibration is
+ loaded into the display hardware just before the instrument starts
+ measurement, after the test window first appears.<br>
+ <br>
+ <a name="K"></a> <span style="font-weight: bold;">-K: </span>If a
+ display video lookup table calibration <a
+ href="File_Formats.html#.cal">.cal</a> file is provided, it will
+ be applied to the test values for each measurement, and also
+ included in the resulting .ti3 data file, so that <a
+ href="colprof.html">colprof</a> can include it as a <span
+ style="font-weight: bold;">vcgt</span> tag in the resulting
+ profile. This is <span style="font-weight: bold;">NOT</span>
+ normally the best way to profile a calibrated display, since the
+ frame buffer may have lower precision than the VideoLUTs output
+ values. This is the way calibration should be applied if MadVR is
+ being used to display the test patches. If a calibration file is not
+ supplied using <b>-k</b> or <b>-K</b>, then the display will be
+ measured in whatever calibration state it is in, and no calibration
+ information is saved to the resulting .ti3 file.<br>
+ If the calibration file provided created using video range encoding
+ (dispcal -E), then the <b>-E</b> option in dispread will be
+ triggered automatically.<br>
+ <br>
+ <a name="V"></a><b>-V:</b> [MSWin] If using MadVR to display test
+ patches, then enable Color Managenent (3dLut). This would be used
+ for verification measurement.<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument, or 10% of the width of the
+ display if the display size is unknown. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="E"></a> The <span style="font-weight: bold;">-E</span>
+ flag causes the test values to be scaled to the Video RGB encoding
+ range of 16/255 to 235/255. If the calibration file provided using
+ the <b>-k</b> or <b>-K</b> flag was created using video range
+ encoding, then this option will be triggered automatically. This
+ will also set quantization of 8 bits (see -Z flag below). If your
+ video connection is better than 8 bits (ie. 10 or 12 bits), then you
+ may wish to raise this default.<br>
+ <br>
+ <a name="Z"></a> <b>-Z nbits </b>Normally the target device values
+ are floating point numbers that may get rounded and quantized in the
+ process of printing them or reproducing them on the display device.
+ If some of this quantization can be accounted for, it may improve
+ the accuracy of the resulting profile, and the <span
+ style="font-weight: bold;">Q</span> parameter allows this
+ quantization to be specified. The parameter is the number of binary
+ digits (bits) that the device values should be quantized to. An idea
+ of the number of bits of precision that makes its way to your
+ display can be obtained by using <a href="dispcal.html#R">dispcal
+ -R</a> If Video encoding is selected (see -E flag above), then 8
+ bits is selected by default. On systems using an VGA connection or
+ Display Port with a graphics card with VideoLUT entries with greater
+ than 8 bits depth, or if using the MadVR rendered with dithering,
+ then a higher bit depth is typically possible.<br>
+ <br>
+ <a name="n"></a><span style="font-weight: bold;">-n</span>: When
+ running on a UNIX based system that used the X11 Windowing System, <b>dispread</b>
+ normally selects the override redirect so that the test window will
+ appear above any other windows on the display. On some systems this
+ can interfere with window manager operation, and the <b>-n</b>
+ option turns this behaviour off.<br>
+ <br>
+ <a name="J"></a> The -<span style="font-weight: bold;">J</span>
+ option runs through the black and sensor relative calibration
+ routines for the Xrite DTP92 and DTP94 instrument, the black level
+ calibration for the Eye-One Display 1, and a CRT frequency
+ calibration for the Eye-One Display 2. For the black calibration the
+ instrument should be placed on an opaque, black surface, and any
+ stray light should be avoided by placing something opaque over the
+ instrument. If a Spectrolino is being used, then a white and black
+ calibration will always be performed before the instrument can be
+ placed on the display, unless the <a href="#N">-N</a> flag is used.
+ Generally it is not necessary to do a calibration every time an
+ instrument is used, just now and again. There is no point in
+ doing&nbsp; a CRT frequency calibration, as this will be done
+ automatically at the commencement of patch reading.<br>
+ <br>
+ <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it. See <a href="instruments.html">Operation of particular
+ instruments</a> for more details. This may give better accuracy
+ for display measurements.<br>
+ <br>
+ <a name="w"></a>The <b>-w</b> flag disables the normalisation of
+ the white patch value to 100.0, resulting in values that are in
+ cd/m^2. This is mainly for diagnostic purposes.<br>
+ <br>
+ <a name="X1"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccmx</span></span> option reads
+ a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
+ from the given file, and applies it to the colorimeter instruments
+ readings. This can improve a colorimeters accuracy for a particular
+ type of display. A list of contributed <span style="font-weight:
+ bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
+ <br>
+ <a name="X2"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccss</span></span> option reads
+ a <a href="File_Formats.html#.ccss">Colorimeter Calibration
+ Spectral Sample</a> from the given file, and uses it to set the
+ colorimeter instruments calibration. This will only work with
+ colorimeters that rely on sensor spectral sensitivity calibration
+ information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
+ or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
+ Spyder 5</span>).This can improve a colorimeters accuracy for a
+ particular type of display.<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values from spectral readings or using a colorimeter
+ that has CCSS capability. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
+ observer that has been adjusted using a 3x3 matrix to better agree
+ with the 1931 2 degree observer.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you select
+ anything other than the default 1931 2 degree observer, that the Y
+ values will not be cd/m^2, due to the Y curve not being the CIE 1924
+ photopic V(&#955;) luminosity function.<br>
+ <br>
+ <a name="I"></a> The -<span style="font-weight: bold;">I <span
+ style="font-style: italic;">b|w</span></span> options invoke
+ instrument black level, and display white level compensation
+ (respectively). Instrument black level drift compensation attempts
+ to combat instrument black calibration drift by using a display
+ black test patch as a reference. If an instrument is not
+ acclimatised sufficiently to the measurement conditions, changes in
+ temperature can affect the black readings. Display white level drift
+ compensation attempts to combat changes in display brightness as it
+ warms up by measuring a white patch every so often, and using it to
+ normalise all the other readings. If just instrument black drift
+ compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
+ If just display white level compensation is needed, use <span
+ style="font-weight: bold;">-Iw</span>. If both are needed, use <span
+ style="font-weight: bold;">-Ibw</span> or <span
+ style="font-weight: bold;">-Iwb</span>.<br>
+ <br>
+ <a name="YR"></a> The -<span style="font-weight: bold;">Y R:<i>rate</i></span>
+ options overrides calibration of the instrument refresh rate. This
+ may be useful if the instrument supports this function and the
+ refresh rate cannot be accurately calibrated from the display
+ itself.<br>
+ <span style="font-weight: bold;">&nbsp;<br>
+ </span><a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
+ option uses a non-adaptive integration time emission measurement
+ mode, if the instrument supports it, such as the Eye-One Pro,
+ ColorMunki, i1d3 and K10. By default an adaptive integration time
+ measurement mode will be used for emission measurements, but some
+ instruments support a fixed integration time mode that can be used
+ with display devices. This may give faster measurement times, but
+ may also give less accurate low level readings.<br>
+ <br>
+ <a name="Yp"></a> The -<span style="font-weight: bold;">Y p</span>
+ option skips asking the user to place the instrument on the display.
+ Normally a grey patch is displayed, and then the user is asked to
+ confirm that the instrument is in place, so that readings can
+ commence. This flag disables that check. This may be useful in
+ automating certain operations.<br>
+ <span style="font-weight: bold;"><br>
+ </span><a name="C"></a> The -<span style="font-weight: bold;">C</span>
+ <span style="font-weight: bold;">"command" </span>option allows a
+ method of relaying each test value to some other display than that
+ on the system running dispread (for instance, a photo frame, PDA
+ screen etc.), by causing the given command to be invoked to the
+ shell, with six arguments. The first three arguments are the RGB
+ test color as integers in the range 0 to 255, the second three
+ parameters are the RGB test color as floating point numbers in the
+ range 0.0 to 1.0. The script or tool should relay the given color to
+ the screen in some manner (e.g. by generating a raster file of the
+ given color and sending it to the display being profiled), before
+ returning. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of gathering each test value from some external source, such
+ as an instrument that is not directly supported by Argyll. The given
+ command is involked to the shell, with six arguments. The first
+ three arguments are the RGB test color as integers in the range 0 to
+ 255, the second three parameters are the RGB test color as floating
+ point numbers in the range 0.0 to 1.0. The script or tool should
+ create a file called <span style="font-weight: bold;">"command.meas</span>"
+ that contains the XYZ values for the given RGB (or measured from the
+ test window) in cd/m^2 as three numbers separated by spaces, before
+ returning. If the command returns a non-zero return value, dispread
+ will abort. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="x"></a> The <b>-x</b> flag causes dispread to expect
+ values to be manually entered for each reading, rather than using an
+ instrument to do the measurements.&nbsp; This mode is ideal if your
+ instrument is not supported by Argyll. XYZ values should be entered.
+ It is possible to navigate about the test values being measured, so
+ as to do them in any order, as well as re-do values, in case of any
+ mistakes.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="p1"></a> The final parameter on the command line is the
+ base filename for the <a href="File_Formats.html#.ti1">.ti1</a>
+ input file, and the <a href="File_Formats.html#.ti3">.ti3</a>
+ output file. <b>dispread</b> will add the .ti1 and .ti3 extensions
+ automatically.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ If a large number of patches is being read, the screensaver on many
+ systems can interfere with the operation of dispread. It is
+ therefore advisable in these cases to manually turn off the
+ screensaver before commencing the measurements.<br>
+ <br>
+ If communications break down with a USB connected instrument, you
+ may have to unplug it, and plug it in again to recover.<br>
+ <br>
+ Some systems (Apple OSX in particular) have a special set of user
+ interface controls ("Universal Access") that allows altering the
+ display in ways designed to assist visually impaired users, by
+ increasing contrast etc. This will interfere badly with any attempts
+ to calibrate or profile such a system, and must be turned off in
+ order to do so. Note that certain magic keyboard sequences can turn
+ this on by accident.<br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/dispwin.html b/doc/dispwin.html
index dac6b8e..05db989 100644
--- a/doc/dispwin.html
+++ b/doc/dispwin.html
@@ -1,38 +1,38 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>dispwin</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- </head>
- <body>
- <h2><b>spectro/dispwin</b></h2>
- <h3>Summary</h3>
- This tool has several different but related functions. When given as
- a file argument an ICC profile containing vcgt "gamma" curves, or an
- Argyll video calibration .cal file, it will load that calibration
- into the chosen display. It can also install or uninstall a profile
- in the system for the chosen display, or set the display calibration
- to that in the currently installed system profile. By default it
- displays a test window the same as that used by dispcal and
- dispread, to test this functionality. It can also be used to test
- the ability to load video card LUT curves to each display, and to
- test how the console Bell will sound when used with some instruments
- (ie. Eye-One Pro).<br>
- <br>
- [Note that in OS X 10.7 Lion, changes to the default system profile
- permissions mean that you can't set a calibration persistently when
- the default system profile is being used, unless you run as root
- (ie. use sudo). Note that you do <span style="font-weight: bold;">not</span>
- need to run as root to install a user profile (-Su, the default
- install type.)]<br>
- <h3>Usage</h3>
- <font size="-1"><span style="font-family: monospace;">dispwin
- [options] [<span style="font-style: italic;">calfile</span>]</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#v">-v</a><span
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispwin</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispwin</b></h2>
+ <h3>Summary</h3>
+ This tool has several different but related functions. When given as
+ a file argument an ICC profile containing vcgt "gamma" curves, or an
+ Argyll video calibration .cal file, it will load that calibration
+ into the chosen display. It can also install or uninstall a profile
+ in the system for the chosen display, or set the display calibration
+ to that in the currently installed system profile. By default it
+ displays a test window the same as that used by dispcal and
+ dispread, to test this functionality. It can also be used to test
+ the ability to load video card LUT curves to each display, and to
+ test how the console Bell will sound when used with some instruments
+ (ie. Eye-One Pro).<br>
+ <br>
+ [Note that in OS X 10.7 Lion, changes to the default system profile
+ permissions mean that you can't set a calibration persistently when
+ the default system profile is being used, unless you run as root
+ (ie. use sudo). Note that you do <span style="font-weight: bold;">not</span>
+ need to run as root to install a user profile (-Su, the default
+ install type.)]<br>
+ <h3>Usage</h3>
+ <font size="-1"><span style="font-family: monospace;">dispwin
+ [options] [<span style="font-style: italic;">calfile</span>]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
Verbose
@@ -51,18 +51,18 @@ Verbose
-
- mode<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#display">-display displayname</a><span
- style="font-family: monospace;"> [<span style="font-weight:
- bold;">X11 only</span>] Choose X11 display name<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- [<span style="font-weight: bold;">X11 only</span>] Choose the
- display from the following list (default 1),<br>
+
+ mode<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [<span style="font-weight:
+ bold;">X11 only</span>] Choose X11 display name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [<span style="font-weight: bold;">X11 only</span>] Choose the
+ display from the following list (default 1),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
and
optionally
@@ -81,9 +81,9 @@ optionally
-
- choose a different display m for Video LUT access.<br>
- </span></font><font size="-1"><span style="font-family:
+
+ choose a different display m for Video LUT access.<br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
[Not
X11]
@@ -102,9 +102,9 @@ X11]
-
- Choose the display from the following list (default 1)<br>
- </span></font><span style="font-family: monospace;">&nbsp;<a
+
+ Choose the display from the following list (default 1)<br>
+ </span></font><span style="font-family: monospace;">&nbsp;<a
href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -119,22 +119,22 @@ X11]
-
- Display via a web server at port (default 8080)</span><br>
- <span style="font-family: monospace;">&nbsp;<a
- href="dispwin.html#dmadvr">-dmadvr</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- [MSWin] Display via MadVR Video Renderer</span><br>
+
+ Display via a web server at port (default 8080)</span><br>
+ <span style="font-family: monospace;">&nbsp;<a
+ href="dispwin.html#dmadvr">-dmadvr</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [MSWin] Display via MadVR Video Renderer</span><br>
<tt>&nbsp;</tt><tt><a href="#dcc">-dcc[:n]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- </tt><tt></tt><tt>Display via n'th ChromeCast (default 1, ? for
- list)</tt><br style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;<a href="#P">-P
- ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
- and scale it</span><br style="font-family: monospace;">
+
+ </tt><tt></tt><tt>Display via n'th ChromeCast (default 1, ? for
+ list)</tt><br style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;<a href="#P">-P
+ ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
+ and scale it</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ho,vi:
0.0
@@ -153,9 +153,9 @@ ho,vi:
-
- = left/top, 0.5 = center, 1.0 = right/bottom etc.</span><br
- style="font-family: monospace;">
+
+ = left/top, 0.5 = center, 1.0 = right/bottom etc.</span><br
+ style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ss:
0.5
@@ -174,8 +174,8 @@ ss:
-
- = half, 1.0 = normal, 2.0 = double etc.<br>
+
+ = half, 1.0 = normal, 2.0 = double etc.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -188,10 +188,10 @@ ss:
-
- ss,vs: = optional horizontal, vertical scale.<br>
- &nbsp;</span></font><font size="-1"><span style="font-family:
- monospace;"><a href="#F">-F</a>
+
+ ss,vs: = optional horizontal, vertical scale.<br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><a href="#F">-F</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Fill
whole
@@ -210,10 +210,10 @@ whole
-
- screen with black background</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
- size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
+
+ screen with black background</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
+ size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -221,25 +221,25 @@ whole
-
- </span></font><small><span style="font-family: monospace;">Video
- encode output as (16-235)/255 "TV" levels</span></small><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#i">-i</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Run forever with random values<br>
- &nbsp;<a href="#G">-G <span style="font-style: italic;">filename</span></a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Display RGB
- colors from CGATS file<br>
- &nbsp;</span></font><font size="-1"><a style="font-family:
- monospace;" href="#m">-m</a><span style="font-family:
- monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Manually step through colors</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ </span></font><small><span style="font-family: monospace;">Video
+ encode output as (16-235)/255 "TV" levels</span></small><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#i">-i</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Run forever with random values<br>
+ &nbsp;<a href="#G">-G <span style="font-style: italic;">filename</span></a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Display RGB
+ colors from CGATS file<br>
+ &nbsp;</span></font><font size="-1"><a style="font-family:
+ monospace;" href="#m">-m</a><span style="font-family:
+ monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Manually step through colors</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#r">-r</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Test
just
@@ -258,10 +258,10 @@ just
-
- video LUT loading &amp; Beeps<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#n">-n</a>
+
+ video LUT loading &amp; Beeps<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#n">-n</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Test
native
@@ -280,8 +280,8 @@ native
-
- display values (rather than through Video LUT&nbsp; and C.M.)<br>
+
+ display values (rather than through Video LUT&nbsp; and C.M.)<br>
&nbsp;<a href="#s">-s <span style="font-style: italic;">filename.cal</span></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Save
the
@@ -300,10 +300,10 @@ the
-
- currently loaded Video LUT to 'filename'<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#c">-c</a>
+
+ currently loaded Video LUT to 'filename'<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#c">-c</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Load
a
@@ -322,11 +322,11 @@ a
-
- linear display calibration (clear calibration)</span></font><font
- size="-1"><span style="font-family: monospace;"><br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#V">-V</a>
+
+ linear display calibration (clear calibration)</span></font><font
+ size="-1"><span style="font-family: monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#V">-V</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Verify
that
@@ -345,10 +345,10 @@ that
-
- calfile/profile cal. is currently loaded in LUT<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#I">-I</a>
+
+ calfile/profile cal. is currently loaded in LUT<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#I">-I</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -365,11 +365,11 @@ that
-
- </span></font><font size="-1"><span style="font-family:
- monospace;">Install profile for display and use it's calibration<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#U">-U</a>
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Install profile for display and use it's calibration<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#U">-U</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -386,9 +386,9 @@ that
-
- </span></font><font size="-1"><span style="font-family:
- monospace;">Un-install profile for display<br>
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Un-install profile for display<br>
&nbsp;<a href="#S">-S d</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Specify
the
@@ -407,8 +407,8 @@ the
-
- install/uninstall scope for OS X [nlu] or Vista [lu]<br>
+
+ install/uninstall scope for OS X [nlu] or Vista [lu]<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
d
is
@@ -427,11 +427,11 @@ is
-
- one of: n = network, l = local system, u = user (default)<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;"></span></font><font size="-1"><span
- style="font-family: monospace;">&nbsp;<a href="#L">-L</a>
+
+ one of: n = network, l = local system, u = user (default)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;">&nbsp;<a href="#L">-L</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -448,11 +448,11 @@ is
-
- </span></font><font size="-1"><span style="font-family:
- monospace;">Load installed profiles cal. into Video LUT<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#X">-<font size="-1">X</font></a>
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Load installed profiles cal. into Video LUT<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#X">-<font size="-1">X</font></a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -469,11 +469,11 @@ is
-
- [<span style="font-weight: bold;">X11 only</span>] Run in daemon
- loader mode for given X11 server <br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
+
+ [<span style="font-weight: bold;">X11 only</span>] Run in daemon
+ loader mode for given X11 server <br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
href="#D">-D [level]</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Print
debug
@@ -492,14 +492,14 @@ debug
-
- diagnostics to stderr</span></font><font size="-1"><span
- style="font-family: monospace;"></span></font><font size="-1"><span
- style="font-family: monospace;"></span><span style="font-family:
- monospace;"><br>
- &nbsp;</span></font><a style="font-family: monospace;"
- href="#p1"><font size="-1"><span style="font-family: monospace;"></span></font></a><font
- size="-1"><a style="font-family: monospace;" href="#p1"><i>calfile</i></a><span
+
+ diagnostics to stderr</span></font><font size="-1"><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ &nbsp;</span></font><a style="font-family: monospace;"
+ href="#p1"><font size="-1"><span style="font-family: monospace;"></span></font></a><font
+ size="-1"><a style="font-family: monospace;" href="#p1"><i>calfile</i></a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Load
display
@@ -518,60 +518,60 @@ display
-
- calibration (<a href="cal_format.html">.cal</a> or .icm) into
- LUT, and exit.</span><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></font><br>
- <br>
- <h3>Comments<br>
- </h3>
- <a name="v"></a> The <b>-v</b> flag makes the program more
- verbose..<br>
- <br>
- <a name="display"></a><span style="font-weight: bold;">display</span>:
- When running on a UNIX based system that used the X11 Windowing
- System, <b>dispwin</b> will by default use the $DISPLAY environment
- variable to determine which display and screen to read from. This
- can be overridden by supplying an X11 display name to the <span
- style="font-weight: bold;">-display</span> option. Note that if
- Xinerama is active, you can't select the screen using $DISPLAY or
- -display, you have to select it using the <span style="font-weight:
- bold;">-d</span> parameter.<br>
- <br>
- <a name="d"></a><span style="font-weight: bold;">-d</span>: By
- default the location of the test window will be the main display. If
- the system has more than one display or screen, an alternate
- display/screen can be selected with the <span style="font-weight:
- bold;">-d</span> parameter. If you invoke <span
- style="font-weight: bold;">dispwin</span> so as to display the
- usage information (i.e. "dispcal -?" or "dispcal --"), then the
- discovered displays/screens will be listed. Multiple displays may
- not be listed if they appear as a single display to the operating
- system (ie. the multi-display support is hidden in the video card
- driver). On UNIX based system that used the X11 Windowing System,
- the <span style="font-weight: bold;">-d</span> parameter will
- override the screen specified by the $DISPLAY or <span
- style="font-weight: bold;">-display</span> parameter.<br>
- <span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
- display are not accessible (i.e. no hardware calibration
- capability), <span style="font-weight: bold;">dispwin</span> will
- will issue a warning or fail when it attempts to access them.<br>
- <br>
- On X11 the inability to access VideoLUTs could be because you are
- trying to access a remote display, and the remote display doesn't
- support the XF86VidMode extension, or perhaps you are running
- multiple monitors using NVidia TwinView, or MergedFB, and trying to
- access anything other than the primary monitor. TwinView and
- MergedFB don't properly support the XF86VidMode extension for
- multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
- to test whether the VideoLUTs are accessible for a particular
- display. See also below, on how to select a different display for
- VideoLUT access. Also note that dispcal will fail if the Visual
- depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
- 256 entries per color component, so the Visual generally needs to be
- 24 bits, 8 bits per color component.<br>
- <br>
+
+ calibration (<a href="cal_format.html">.cal</a> or .icm) into
+ LUT, and exit.</span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></font><br>
+ <br>
+ <h3>Comments<br>
+ </h3>
+ <a name="v"></a> The <b>-v</b> flag makes the program more
+ verbose..<br>
+ <br>
+ <a name="display"></a><span style="font-weight: bold;">display</span>:
+ When running on a UNIX based system that used the X11 Windowing
+ System, <b>dispwin</b> will by default use the $DISPLAY environment
+ variable to determine which display and screen to read from. This
+ can be overridden by supplying an X11 display name to the <span
+ style="font-weight: bold;">-display</span> option. Note that if
+ Xinerama is active, you can't select the screen using $DISPLAY or
+ -display, you have to select it using the <span style="font-weight:
+ bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a><span style="font-weight: bold;">-d</span>: By
+ default the location of the test window will be the main display. If
+ the system has more than one display or screen, an alternate
+ display/screen can be selected with the <span style="font-weight:
+ bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispwin</span> so as to display the
+ usage information (i.e. "dispcal -?" or "dispcal --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or <span
+ style="font-weight: bold;">-display</span> parameter.<br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
+ display are not accessible (i.e. no hardware calibration
+ capability), <span style="font-weight: bold;">dispwin</span> will
+ will issue a warning or fail when it attempts to access them.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
<a name="dnm"></a><span style="font-weight: bold;">-d n[,m]</span>Because
of
the
@@ -590,257 +590,257 @@ the
-
- difficulty cause by TwinView and MergedFB in X11 based systems, you
- can optionally specify a separate display number after the display
- that is going to be used to present test patches, for accessing the
- VideoLUT hardware. This must be specified as a single string, e.g. <span
- style="font-weight: bold;">-d 1,2</span> . Some experimentation
- may be needed on such systems, to discover what screen has access to
- the VideoLUT hardware, and which screens the test patches appear on.
- You may be able to calibrate one screen, and then share the
- calibration with another screen. Profiling can be done independently
- to calibration.<br>
- <br>
- <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
- <span style="font-weight: bold;">-dweb:<i>port</i></span> starts a
- standalone web server on your machine, which then allows a local or
- remote web browser to display the the color test patches. By default
- port <span style="font-weight: bold;">8080</span> is used, but this
- can be overridden by appending a <span style="font-weight: bold;">:</span>
- and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
- The URL will be <span style="font-weight: bold;">http://</span>
- then name of the machine or its I.P. address followed by a colon and
- the port number - e.g something like <span style="font-weight:
- bold;">http://192.168.0.1:8080</span>. If you use the verbose
- option (<span style="font-weight: bold;">-v</span>) then a likely
- URL will be printed once the server is started, or you could run <span
- style="font-weight: bold;">ipconfig</span> (MSWin) or <span
- style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
- and identify an internet address for your machine that way. <b>JavaScript</b>
- needs to be enabled in your web browser for this to work. You may
- have to modify any firewall to permit port 8080 to be accessed on
- your machine.<br>
- <br>
- Note that if you use this method of accessing a display, that there
- is no access to the display Video Lookup tables, and that any
- operation that depends on accessing the VideoLUTs will either
- generate a warning or fail.<br>
- <br>
- <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
- [MSWin only] causes test patches to be displayed using the MadVR
- video renderer. Note that will have to start <b>MadTPG</b> before
- running dispread, and that while you can adjust the "Test Pattern
- Configuration" controls, you should <u>not</u> normally alter the
- "Existing Calibration" controls, as dispread will set these
- appropriately. See <a href="#n">-n</a> flag.<br>
- <br>
- <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
- causes test patches to be displayed using and available <a
- href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
- your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
- local network. Note that the ChromeCast as a test patch source is
- probably the<b> least accurate</b> of your choices, since it
- up-samples the test patch and transforms from RGB to YCC and back,
- but should be accurate within ± 1 bit. You may have to modify any
- firewall to permit port 8081 to be accessed on your machine if it
+
+ difficulty cause by TwinView and MergedFB in X11 based systems, you
+ can optionally specify a separate display number after the display
+ that is going to be used to present test patches, for accessing the
+ VideoLUT hardware. This must be specified as a single string, e.g. <span
+ style="font-weight: bold;">-d 1,2</span> . Some experimentation
+ may be needed on such systems, to discover what screen has access to
+ the VideoLUT hardware, and which screens the test patches appear on.
+ You may be able to calibrate one screen, and then share the
+ calibration with another screen. Profiling can be done independently
+ to calibration.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:<i>port</i></span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way. <b>JavaScript</b>
+ needs to be enabled in your web browser for this to work. You may
+ have to modify any firewall to permit port 8080 to be accessed on
+ your machine.<br>
+ <br>
+ Note that if you use this method of accessing a display, that there
+ is no access to the display Video Lookup tables, and that any
+ operation that depends on accessing the VideoLUTs will either
+ generate a warning or fail.<br>
+ <br>
+ <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
+ [MSWin only] causes test patches to be displayed using the MadVR
+ video renderer. Note that will have to start <b>MadTPG</b> before
+ running dispread, and that while you can adjust the "Test Pattern
+ Configuration" controls, you should <u>not</u> normally alter the
+ "Existing Calibration" controls, as dispread will set these
+ appropriately. See <a href="#n">-n</a> flag.<br>
+ <br>
+ <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
+ causes test patches to be displayed using and available <a
+ href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
+ your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
+ local network. Note that the ChromeCast as a test patch source is
+ probably the<b> least accurate</b> of your choices, since it
+ up-samples the test patch and transforms from RGB to YCC and back,
+ but should be accurate within ± 1 bit. You may have to modify any
+ firewall to permit port 8081 to be accessed on your machine if it
falls back to the Default receiver (see <a href="Installing.html">installation
-
- instructions</a> for your platform).<br>
- <br>
- <a name="P"></a> The <span style="font-weight: bold;">-P</span>
- parameter allows you to position and size the test patch window. By
- default it is places in the center of the screen, and sized
- appropriately for the type of instrument, or 10% of the width of the
- display if the display size is unknown.. The <span
- style="font-weight: bold;">ho</span> and <span
- style="font-weight: bold;">vo</span> values govern the horizontal
- and vertical offset respectively. A value of 0.0 positions the
- window to the far left or top of the screen, a value of 0.5
- positions it in the center of the screen (the default), and 1.0
- positions it to the far right or bottom of the screen. If three
- parameters are provided, then the <span style="font-weight: bold;">ss</span>
- parameter is a scale factor for the test window size. A value of 0.5
- for instance, would produce a half sized window. A value of 2.0 will
- produce a double size window. If four parameters are provided, then
- the last two set independent horizontal and vertical scaling
- factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
- specified as a single string (no space between the numbers and the
- comma). For example, to create a double sized test window at the top
- right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
- . To create a window twice as wide as high: <span
- style="font-weight: bold;">-P 1,0,2,1</span>.<br>
- <br>
- <a name="F"></a> The <span style="font-weight: bold;">-F</span>
- flag causes the while screen behind the test window to be masked
- with black. This can aid black accuracy when measuring CRT displays
- or projectors.<br>
- <br>
- <a name="E"></a> The <span style="font-weight: bold;">-E</span>
- flag causes the test values to be scaled to the Video RGB encoding
- range of 16/255 to 235/255. Note that this is not applicable if the
- MadVR render is being used to display patches, as MadVR should be
- configured for Video encoding instead.<br>
- <br>
- By default <span style="font-weight: bold;">dispwin</span> will put
- a test window on the selected display, and display some test colors,
- before darkening&nbsp; then brightening the screen by loading video
- LUT values, test the bell sounds, then restore the original values
- and exit.<br>
- <br>
- If the&nbsp;<a name="i"></a><span style="font-weight: bold;">-i</span>
- flag is set, then <span style="font-weight: bold;">dispwin</span>
- will display the preset sequence, then random test colors forever.<br>
- <br>
- If the&nbsp;<a name="G"></a><span style="font-weight: bold;">-G</span>
- parameter is set, then <span style="font-weight: bold;">dispwin</span>
- will display the sequence of RGB color in the supplied CGATS file,
- e.g. a .ti1 file. Typically this might the used with the <span
- style="font-weight: bold;">-m</span> option to manually measure a
- set of test patches.<br>
- <br>
- If the&nbsp;<a name="m"></a><span style="font-weight: bold;">-m</span>
- flag is set, then <span style="font-weight: bold;">dispwin</span>
- will display the preset sequence then exits, but advances manually
- after each return key.<br>
- <br>
- If the&nbsp;<a name="r"></a><span style="font-weight: bold;">-r</span>
- flag is set, then <span style="font-weight: bold;">dispwin</span>
- will test just the loading of video LUT values by first darkening,
- then lightening the screen, before exiting.<br>
- <br>
- If the&nbsp;<a name="n"></a><span style="font-weight: bold;">-n</span>
- flag is set, then <span style="font-weight: bold;">dispwin</span>
- will display the colors directly on the display, rather than having
- the color values translated through the currently loaded Video LUTs.
- In the case of using the MadVR renderer to display the patches, any
- 3dLut will also be disabled.<br>
- <br>
- <a name="s"></a> If a <span style="font-weight: bold;">-s <span
- style="font-style: italic;">filename.cal</span></span> option is
- used, then rather than displaying a test window, <span
- style="font-weight: bold;">dispwin</span> will save the currently
- loaded calibration curves to the given calibration file. Note that
- other functions such as clearing or loading a calibration can be
- performed after this action.<br>
- <br>
- <a name="c"></a> If a <span style="font-weight: bold;">-c</span>
- flag is used, then rather than displaying a test window, <span
- style="font-weight: bold;">dispwin</span> will load the selected
- display with a linear set of Video LUT curves, effectively clearing
- the calibration, and will then exit. Note that other functions such
- as loading a calibration can be performed after this action.<span
- style="font-style: italic;"></span><br>
- <br>
- <a name="V"></a> If a <span style="font-weight: bold;">-V</span>
- flag is used, then rather than loading the calibration specified as
- the final argument, the currently loaded calibration will be
- verified as being the same as the given calibration file. If this is
- combined with the <span style="font-weight: bold;"><span
- style="font-weight: bold;">-L</span></span> flag, the currently
- loaded calibration will be verified as being the same as the
- installed system profile for the display.<br>
- <br>
- <a name="I"></a><span style="font-weight: bold;">-I</span>: The ICC
- profile specified as the final argument will be installed as the
- default operating system profile for the chosen display, and the
- display calibration will be set to the calibration tag ('vcgt' tag,
- if any) in that profile.. On MSWindows and OS X this means that the
- profile will be copied to the appropriate color profile directory
- and registered with the operating system. For Linux X11 systems, the
- profile will be installed using the <a href="ucmm.html">ucmm</a>
- convention, and the X11 _ICC_PROFILE property in the root window,
- and also the the XrandR 1.2 X11 _ICC_PROFILE output property on
- systems that are running XrandR 1.2 or later. The latter is
- following this <a
- href="http://www.burtonini.com/computing/x-icc-profiles-spec-0.2.html">convention</a>
- for allowing applications to locate the display profile for a
- particular X11 display, and expands it to accomodate XrandR 1.2.
- Note that for X11 systems, the properties are not persistent, and
- will need to be loaded each time the X11 server is started (see the
- <a href="#L">-L</a> flag). To make sure that the profile calbration
- 'vcgt' tag gets loaded into the Graphics Card at system start,
- please read the guide <a href="dispprofloc.html">here</a>.<br>
- <br>
- <a name="U"></a><span style="font-weight: bold;">-U</span>: The ICC
- profile specified as the final argument will be un-installed as the
- default operating system profile for the chosen display. The display
- calibration will remain unchanged.<br>
- <br>
- <a name="S"></a><span style="font-weight: bold;">-S</span> d: Some
- systems have more than one profile scope that an installed profile
- will apply to, and this parameter allows overriding the default user
- scope. On OS X, there is a choice of three scopes: <span
- style="font-weight: bold;">n</span>: for network scope, if people
- are sharing profiles over a network, <span style="font-weight:
- bold;">l</span>: local system scope, which installs the profile
- for all users of a system, and the default <span
- style="font-weight: bold;">u</span>, which covers just the user
- installing the profile. On Linux or Microsoft Vista, just the local
- system <span style="font-weight: bold;">l</span> and user <span
- style="font-weight: bold;">u</span> scope are available. Note that
- you may need to run dispwin with elevated privileges(sudo) to be
- able to successfully use network or local system scope. This option
- also applies to uninstalling a profile. Note that to install a user
- profile for the root account, you will have to login as root (sudo
- will not achieve this).<br>
- <br>
- <a name="L"></a> <span style="font-weight: bold;">-L</span>: This
- option fetches the current installed system profile for the chosen
- display, and sets the display to the calibration tag ('vcgt' tag, if
- any) in the profile. This is a convenient way of initializing the
- display on system startup from the installed display profile, if the
- system doesn't not do this automatically .<br>
- <br>
- <a name="X"></a> <span style="font-weight: bold;">-X</span>: Daemon
- mode (experimental). When running on a UNIX based system that used
- the X11 Windowing System, this option runs dispwin in a "daemon"
- mode where it monitors the given X11 server, waiting for any changes
- in monitors that may require loading a matching ICC profile (ie.
- such as re-configuring, plugging in a different monitor etc.)&nbsp;
- This only works if XRandR 1.2 is available on the server. By default
- dispwin runs silently, and will not terminate. If the <span
- style="font-weight: bold;">-v</span> option is given, it will emit
- messages to stdout to show what it is doing. When it is first
- invoked, it will load the installed profiles of all the screens of
- the given X11 server.<br>
- <br>
- <a name="D"></a>The <b>-D</b> flag causes diagnostics to be printed
- to stdout. A level can be set between 1 .. 9, that may give
- progressively more verbose information. This can be useful in
- tracking down why an operation fails.<br>
- <br>
- <a name="p1"></a> The final optional parameter on the command line
- is the name of an ICC profile that contains a Video LUT <span
- style="font-weight: bold;">vcgt</span> tag, or an Argyll <a
- href="cal_format.html">.cal</a> format display calibration. If
- this parameter is provided, then the selected display will be loaded
- with the given calibration. If the <span style="font-weight: bold;">-V</span>
- flag was given, then it is verified that this calibration is the
- currently loaded one.&nbsp; This may be useful in initializing a
- system to the current calibration on system startup, although a
- better way may be to install the profile (<span style="font-weight:
- bold;">-I</span> option), and then just use <span
- style="font-weight: bold;">-L</span>. Note that the vcgt tag
- interpretation within Argyll is consistent with that of the
- originators of the tag. Other ICC profile vcgt implementations may
- not be so consistent.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that on an X11 system,
- if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
- is set (ie. set it to "yes"), then the presence of the XRandR 1.2
- extension will be ignored, and other extensions such as Xinerama and
- XF86VidMode extension will be used. This may be a way to work around
- buggy XRandR 1.2 implementations.<br>
- <span style="font-weight: bold;"><br>
- NOTE</span> on MSWin systems that you will have to disable any
- other calibration installer program if you want to be able to
- control calibration using dispwin. Note also that there are other
- programs that will interfere with calibration loading, such as
- igfxpers.exe that gets installed with nVidia "Optimus" technology.<br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ instructions</a> for your platform).<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument, or 10% of the width of the
+ display if the display size is unknown.. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="E"></a> The <span style="font-weight: bold;">-E</span>
+ flag causes the test values to be scaled to the Video RGB encoding
+ range of 16/255 to 235/255. Note that this is not applicable if the
+ MadVR render is being used to display patches, as MadVR should be
+ configured for Video encoding instead.<br>
+ <br>
+ By default <span style="font-weight: bold;">dispwin</span> will put
+ a test window on the selected display, and display some test colors,
+ before darkening&nbsp; then brightening the screen by loading video
+ LUT values, test the bell sounds, then restore the original values
+ and exit.<br>
+ <br>
+ If the&nbsp;<a name="i"></a><span style="font-weight: bold;">-i</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the preset sequence, then random test colors forever.<br>
+ <br>
+ If the&nbsp;<a name="G"></a><span style="font-weight: bold;">-G</span>
+ parameter is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the sequence of RGB color in the supplied CGATS file,
+ e.g. a .ti1 file. Typically this might the used with the <span
+ style="font-weight: bold;">-m</span> option to manually measure a
+ set of test patches.<br>
+ <br>
+ If the&nbsp;<a name="m"></a><span style="font-weight: bold;">-m</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the preset sequence then exits, but advances manually
+ after each return key.<br>
+ <br>
+ If the&nbsp;<a name="r"></a><span style="font-weight: bold;">-r</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will test just the loading of video LUT values by first darkening,
+ then lightening the screen, before exiting.<br>
+ <br>
+ If the&nbsp;<a name="n"></a><span style="font-weight: bold;">-n</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the colors directly on the display, rather than having
+ the color values translated through the currently loaded Video LUTs.
+ In the case of using the MadVR renderer to display the patches, any
+ 3dLut will also be disabled.<br>
+ <br>
+ <a name="s"></a> If a <span style="font-weight: bold;">-s <span
+ style="font-style: italic;">filename.cal</span></span> option is
+ used, then rather than displaying a test window, <span
+ style="font-weight: bold;">dispwin</span> will save the currently
+ loaded calibration curves to the given calibration file. Note that
+ other functions such as clearing or loading a calibration can be
+ performed after this action.<br>
+ <br>
+ <a name="c"></a> If a <span style="font-weight: bold;">-c</span>
+ flag is used, then rather than displaying a test window, <span
+ style="font-weight: bold;">dispwin</span> will load the selected
+ display with a linear set of Video LUT curves, effectively clearing
+ the calibration, and will then exit. Note that other functions such
+ as loading a calibration can be performed after this action.<span
+ style="font-style: italic;"></span><br>
+ <br>
+ <a name="V"></a> If a <span style="font-weight: bold;">-V</span>
+ flag is used, then rather than loading the calibration specified as
+ the final argument, the currently loaded calibration will be
+ verified as being the same as the given calibration file. If this is
+ combined with the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-L</span></span> flag, the currently
+ loaded calibration will be verified as being the same as the
+ installed system profile for the display.<br>
+ <br>
+ <a name="I"></a><span style="font-weight: bold;">-I</span>: The ICC
+ profile specified as the final argument will be installed as the
+ default operating system profile for the chosen display, and the
+ display calibration will be set to the calibration tag ('vcgt' tag,
+ if any) in that profile.. On MSWindows and OS X this means that the
+ profile will be copied to the appropriate color profile directory
+ and registered with the operating system. For Linux X11 systems, the
+ profile will be installed using the <a href="ucmm.html">ucmm</a>
+ convention, and the X11 _ICC_PROFILE property in the root window,
+ and also the the XrandR 1.2 X11 _ICC_PROFILE output property on
+ systems that are running XrandR 1.2 or later. The latter is
+ following this <a
+ href="http://www.burtonini.com/computing/x-icc-profiles-spec-0.2.html">convention</a>
+ for allowing applications to locate the display profile for a
+ particular X11 display, and expands it to accomodate XrandR 1.2.
+ Note that for X11 systems, the properties are not persistent, and
+ will need to be loaded each time the X11 server is started (see the
+ <a href="#L">-L</a> flag). To make sure that the profile calbration
+ 'vcgt' tag gets loaded into the Graphics Card at system start,
+ please read the guide <a href="dispprofloc.html">here</a>.<br>
+ <br>
+ <a name="U"></a><span style="font-weight: bold;">-U</span>: The ICC
+ profile specified as the final argument will be un-installed as the
+ default operating system profile for the chosen display. The display
+ calibration will remain unchanged.<br>
+ <br>
+ <a name="S"></a><span style="font-weight: bold;">-S</span> d: Some
+ systems have more than one profile scope that an installed profile
+ will apply to, and this parameter allows overriding the default user
+ scope. On OS X, there is a choice of three scopes: <span
+ style="font-weight: bold;">n</span>: for network scope, if people
+ are sharing profiles over a network, <span style="font-weight:
+ bold;">l</span>: local system scope, which installs the profile
+ for all users of a system, and the default <span
+ style="font-weight: bold;">u</span>, which covers just the user
+ installing the profile. On Linux or Microsoft Vista, just the local
+ system <span style="font-weight: bold;">l</span> and user <span
+ style="font-weight: bold;">u</span> scope are available. Note that
+ you may need to run dispwin with elevated privileges(sudo) to be
+ able to successfully use network or local system scope. This option
+ also applies to uninstalling a profile. Note that to install a user
+ profile for the root account, you will have to login as root (sudo
+ will not achieve this).<br>
+ <br>
+ <a name="L"></a> <span style="font-weight: bold;">-L</span>: This
+ option fetches the current installed system profile for the chosen
+ display, and sets the display to the calibration tag ('vcgt' tag, if
+ any) in the profile. This is a convenient way of initializing the
+ display on system startup from the installed display profile, if the
+ system doesn't not do this automatically .<br>
+ <br>
+ <a name="X"></a> <span style="font-weight: bold;">-X</span>: Daemon
+ mode (experimental). When running on a UNIX based system that used
+ the X11 Windowing System, this option runs dispwin in a "daemon"
+ mode where it monitors the given X11 server, waiting for any changes
+ in monitors that may require loading a matching ICC profile (ie.
+ such as re-configuring, plugging in a different monitor etc.)&nbsp;
+ This only works if XRandR 1.2 is available on the server. By default
+ dispwin runs silently, and will not terminate. If the <span
+ style="font-weight: bold;">-v</span> option is given, it will emit
+ messages to stdout to show what it is doing. When it is first
+ invoked, it will load the installed profiles of all the screens of
+ the given X11 server.<br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes diagnostics to be printed
+ to stdout. A level can be set between 1 .. 9, that may give
+ progressively more verbose information. This can be useful in
+ tracking down why an operation fails.<br>
+ <br>
+ <a name="p1"></a> The final optional parameter on the command line
+ is the name of an ICC profile that contains a Video LUT <span
+ style="font-weight: bold;">vcgt</span> tag, or an Argyll <a
+ href="cal_format.html">.cal</a> format display calibration. If
+ this parameter is provided, then the selected display will be loaded
+ with the given calibration. If the <span style="font-weight: bold;">-V</span>
+ flag was given, then it is verified that this calibration is the
+ currently loaded one.&nbsp; This may be useful in initializing a
+ system to the current calibration on system startup, although a
+ better way may be to install the profile (<span style="font-weight:
+ bold;">-I</span> option), and then just use <span
+ style="font-weight: bold;">-L</span>. Note that the vcgt tag
+ interpretation within Argyll is consistent with that of the
+ originators of the tag. Other ICC profile vcgt implementations may
+ not be so consistent.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <span style="font-weight: bold;"><br>
+ NOTE</span> on MSWin systems that you will have to disable any
+ other calibration installer program if you want to be able to
+ control calibration using dispwin. Note also that there are other
+ programs that will interfere with calibration loading, such as
+ igfxpers.exe that gets installed with nVidia "Optimus" technology.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/i1proDriver.html b/doc/i1proDriver.html
index 0894f59..e29d639 100644
--- a/doc/i1proDriver.html
+++ b/doc/i1proDriver.html
@@ -1,157 +1,195 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
-<head>
- <title>The i1pro Driver</title>
- <meta http-equiv="content-type"
- content="text/html; charset=ISO-8859-1">
- <meta content="Graeme Gill" name="author">
-</head>
-<body>
-<h2 style="text-decoration: underline; font-weight: bold;">How can I
-have confidence in the i1pro Driver ?<br>
-</h2>
-A question that has been asked is : "<span style="font-weight: bold;">You've
-written your own driver for the Eye-One Pro. How can I have confidence
-that the measurements are accurate, and will match those made with the
-original manufacturers driver </span>?"<br>
-<br>
-This is a quite reasonable question. The following attempts to answer
-it.<br>
-<h4 style="text-decoration: underline;">Why does Argyll use it's own
-i1pro driver ?</h4>
-Primarily because the Original Manufacturers Driver (OMD) isn't
-available for all the platforms that ArgyllCMS supports (Linux in
-particular). A side benefit is that it's possible to tweak many of the
-driver parameters for slightly better results and more flexibility. It
-has also helped in understanding the characteristics and limitations of
-such instruments.<br>
-<h4 style="text-decoration: underline;">Does it match the OMD ?</h4>
-In principle the behaviour should be very similar. While the Argyll
-driver has been written from scratch, it does use exactly the same
-calibration values from<br>
-inside the instrument, and attempts to use the calibration values and
-process the raw instrument readings in an equivalent manner to that of
-the OMD.<br>
-<br>
-But the proof of the pudding is in the measuring, so to actually verify
-this, the following experiment was conducted:<br>
-<br>
-The Argyll version used was V1.2.0<br>
-<br>
-The Macbeth 24 patch ColorChecker was used as a sample target. For each
-patch (and the calibration tile), the following steps were performed:<br>
-<br>
-1) Place the instrument on the calibration tile.<br>
-<br>
-2) Use Argyll spotread to calibrate the Argyll driver.<br>
-<br>
-3) Change drivers to the OMD.<br>
-<br>
-4) Use the OMD to calibrate the instrument.<br>
-<br>
-5) Move the instrument to the patch on the ColorChecker.<br>
-<br>
-6) Read the color using the OMD.<br>
-<br>
-7) Change the back to the Argyll driver.<br>
-<br>
-8) Using the calibration made in step 2), read the color using Argyll.<br>
-<br>
-Each calibration or reading was performed 15 seconds from the previous
-one, to put the instrument lamp in a repeatable state.<br>
-The instrument was kept in exactly the same position for calibration
-and patch measurement with the two drivers.<br>
-(The whole idea is to reduce all other sources of error, other than the
-driver itself.)<br>
-<br>
-This measurement was repeated just once for each patch + the
-calibration tile. This was done in one run, and the readings were not
-specially selected.<br>
-<h4 style="text-decoration: underline;">Results:</h4>
-The following D50 L*a*b* values were recorded for each measurement:<br>
-<br>
-A) &nbsp;&nbsp; The OMD internally calculated L*a*b* value<br>
-B) &nbsp;&nbsp; The L*a*b* value calculated by Argyll from the OMD
-spectral values.<br>
-C) &nbsp;&nbsp; The L*a*b* value calculated from the Argyll measured
-spectral values.<br>
-D) &nbsp;&nbsp; The L*a*b* value calculated from the Argyll
-Hi-Resolution mode measured spectral values.<br>
-<br>
-<span style="text-decoration: underline;">A is compare to B, to check
-that the spectral to standard observer calculations are equivalent.</span><br>
-<br>
-&nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of 0.006,
-with a maximum of 0.012.<br>
-<br>
-&nbsp;&nbsp;&nbsp; This shows that there is very close agreement in the
-way spectral values are converted to XYZ and L*a*b*.<br>
-<br>
-<span style="text-decoration: underline;">B is compared to C to check
-that the Argyll driver behaves the same as the OMD.</span><br>
-<br>
-&nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of 0.028,
-with a maximum of 0.051.<br>
-<br>
-&nbsp;&nbsp;&nbsp; This shows that the OMD and Argyll driver are in
-close agreement in spectral measurement.<br>
-&nbsp;&nbsp;&nbsp; This error is an order of magnitude smaller than
-uniformity induced errors typical in the media being measured.<br>
-<br>
-<span style="text-decoration: underline;">A is compared to C to check
-that the Argyll driver and spectral to XYZ differences don't compound.</span><br>
-<br>
-&nbsp;&nbsp;&nbsp; The result was an <span style="font-weight: bold;">average</span>
-Delta E (CIE76) of <span style="font-weight: bold;">0.026</span>, with
-a <span style="font-weight: bold;">maximum</span> of <span
- style="font-weight: bold;">0.048</span>.<br>
-<br>
-&nbsp;&nbsp;&nbsp; Rather than compounding, any spectral to XYZ
-differences tend to cancel
-out slightly. This is the <span style="font-weight: bold;">bottom line</span>
-experimental difference between
-the two drivers. The actual underlying difference may in fact be less
-than this, but it would be necessary to do multiple test runs to
-filter out experimental error.<br>
-<br>
-<span style="text-decoration: underline;">C is compare to D to check
-that the Argyll Hi-Resolution mode is behaving reasonably.</span><br>
-<br>
-&nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of 0.158,
-with a maximum of 0.353.<br>
-<br>
-&nbsp;&nbsp;&nbsp; Because the ColorChecker samples have relatively
-smooth reflectance spectra, it can be expected that<br>
-&nbsp;&nbsp;&nbsp; the normal and Hi-Res mode results should be fairly
-similar. And indeed, this is the case. The biggest<br>
-&nbsp;&nbsp;&nbsp; differences are for patches
-with the largest spectral transitions in them, which is to be expected
-as the<br>
-&nbsp;&nbsp;&nbsp; Hi-Res measurement more
-closely follows the spectral shape, while the differences for
-spectrally flat<br>
-&nbsp;&nbsp;&nbsp; patches is neglegable, since both can follow the
-spectral shape well.<br>
-<br>
-Example Yellow-Green Patch, Hi-Res &amp; Normal spectrum:<br>
-<img style="width: 709px; height: 259px;"
- alt="Yellow-Green patch, Hi-Res vs. Normal" src="YellowGreen.jpg"><br>
-<br>
-<h4 style="text-decoration: underline;">Conclusions:</h4>
-The experimental average difference of <span style="font-weight: bold;">0.026</span>
-Delta E76 shown above provides evidence that despite using a completely
-different instrument driver to that supplied with the instrument, the
-ArgyllCMS Eye-One pro measurement values have comparable accuracy, and
-can be relied upon to match measurements made using the original
-manufactures driver.<br>
-<h4 style="text-decoration: underline;">Raw Data:</h4>
-The raw data is available in this <a href="i1proDriver.xls">spread
-sheet</a>.<br>
-<br>
-<br>
-<br>
-<br>
-<br>
-<br>
-</body>
+ <head>
+ <title>The i1pro Driver</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta content="Graeme Gill" name="author">
+ </head>
+ <body>
+ <h2 style="text-decoration: underline; font-weight: bold;">How can I
+ have confidence in the i1pro Driver ?<br>
+ </h2>
+ A question that has been asked is : "<span style="font-weight:
+ bold;">You've
+ written your own driver for the Eye-One Pro. How can I have
+ confidence
+ that the measurements are accurate, and will match those made with
+ the
+ original manufacturers driver </span>?"<br>
+ <br>
+ This is a quite reasonable question. The following attempts to
+ answer
+ it.<br>
+ <h4 style="text-decoration: underline;">Why does Argyll use it's own
+ i1pro driver ?</h4>
+ Primarily because the Original Manufacturers Driver (OMD) isn't
+ available for all the platforms that ArgyllCMS supports (Linux in
+ particular). A side benefit is that it's possible to tweak many of
+ the
+ driver parameters for slightly better results and more flexibility.
+ It
+ has also helped in understanding the characteristics and limitations
+ of
+ such instruments.<br>
+ <h4 style="text-decoration: underline;">Does it match the OMD ?</h4>
+ In principle the behaviour should be very similar. While the Argyll
+ driver has been written from scratch, it does use exactly the same
+ calibration values from<br>
+ inside the instrument, and attempts to use the calibration values
+ and
+ process the raw instrument readings in an equivalent manner to that
+ of
+ the OMD.<br>
+ <br>
+ But the proof of the pudding is in the measuring, so to actually
+ verify
+ this, the following experiment was conducted:<br>
+ <br>
+ The Argyll version used was V1.2.0<br>
+ The OMD is the original version prior to the introduction of the
+ i1pro2, and hence reporting the native instrument measurements,
+ rather than applying a conversion to the XRGA standard<br>
+ <br>
+ The Macbeth 24 patch ColorChecker was used as a sample target. For
+ each
+ patch (and the calibration tile), the following steps were
+ performed:<br>
+ <br>
+ 1) Place the instrument on the calibration tile.<br>
+ <br>
+ 2) Use Argyll spotread to calibrate the Argyll driver.<br>
+ <br>
+ 3) Change drivers to the OMD.<br>
+ <br>
+ 4) Use the OMD to calibrate the instrument.<br>
+ <br>
+ 5) Move the instrument to the patch on the ColorChecker.<br>
+ <br>
+ 6) Read the color using the OMD.<br>
+ <br>
+ 7) Change the back to the Argyll driver.<br>
+ <br>
+ 8) Using the calibration made in step 2), read the color using
+ Argyll.<br>
+ <br>
+ Each calibration or reading was performed 15 seconds from the
+ previous
+ one, to put the instrument lamp in a repeatable state.<br>
+ The instrument was kept in exactly the same position for calibration
+ and patch measurement with the two drivers.<br>
+ (The whole idea is to reduce all other sources of error, other than
+ the
+ driver itself.)<br>
+ <br>
+ This measurement was repeated just once for each patch + the
+ calibration tile. This was done in one run, and the readings were
+ not
+ specially selected.<br>
+ <h4 style="text-decoration: underline;">Results:</h4>
+ The following D50 L*a*b* values were recorded for each measurement:<br>
+ <br>
+ A) &nbsp;&nbsp; The OMD internally calculated L*a*b* value<br>
+ B) &nbsp;&nbsp; The L*a*b* value calculated by Argyll from the OMD
+ spectral values.<br>
+ C) &nbsp;&nbsp; The L*a*b* value calculated from the Argyll measured
+ spectral values.<br>
+ D) &nbsp;&nbsp; The L*a*b* value calculated from the Argyll
+ Hi-Resolution mode measured spectral values.<br>
+ <br>
+ <span style="text-decoration: underline;">A is compare to B, to
+ check
+ that the spectral to standard observer calculations are
+ equivalent.</span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of
+ 0.006,
+ with a maximum of 0.012.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; This shows that there is very close agreement in
+ the
+ way spectral values are converted to XYZ and L*a*b*.<br>
+ <br>
+ <span style="text-decoration: underline;">B is compared to C to
+ check
+ that the Argyll driver behaves the same as the OMD.</span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of
+ 0.028,
+ with a maximum of 0.051.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; This shows that the OMD and Argyll driver are in
+ close agreement in spectral measurement.<br>
+ &nbsp;&nbsp;&nbsp; This error is an order of magnitude smaller than
+ uniformity induced errors typical in the media being measured.<br>
+ <br>
+ <span style="text-decoration: underline;">A is compared to C to
+ check
+ that the Argyll driver and spectral to XYZ differences don't
+ compound.</span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; The result was an <span style="font-weight:
+ bold;">average</span>
+ Delta E (CIE76) of <span style="font-weight: bold;">0.026</span>,
+ with
+ a <span style="font-weight: bold;">maximum</span> of <span
+ style="font-weight: bold;">0.048</span>.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rather than compounding, any spectral to XYZ
+ differences tend to cancel
+ out slightly. This is the <span style="font-weight: bold;">bottom
+ line</span>
+ experimental difference between
+ the two drivers. The actual underlying difference may in fact be
+ less
+ than this, but it would be necessary to do multiple test runs to
+ filter out experimental error.<br>
+ <br>
+ <span style="text-decoration: underline;">C is compare to D to check
+ that the Argyll Hi-Resolution mode is behaving reasonably.</span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of
+ 0.158,
+ with a maximum of 0.353.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Because the ColorChecker samples have relatively
+ smooth reflectance spectra, it can be expected that<br>
+ &nbsp;&nbsp;&nbsp; the normal and Hi-Res mode results should be
+ fairly
+ similar. And indeed, this is the case. The biggest<br>
+ &nbsp;&nbsp;&nbsp; differences are for patches
+ with the largest spectral transitions in them, which is to be
+ expected
+ as the<br>
+ &nbsp;&nbsp;&nbsp; Hi-Res measurement more
+ closely follows the spectral shape, while the differences for
+ spectrally flat<br>
+ &nbsp;&nbsp;&nbsp; patches is neglegable, since both can follow the
+ spectral shape well.<br>
+ <br>
+ Example Yellow-Green Patch, Hi-Res &amp; Normal spectrum:<br>
+ <img style="width: 709px; height: 259px;" alt="Yellow-Green patch,
+ Hi-Res vs. Normal" src="YellowGreen.jpg"><br>
+ <br>
+ <h4 style="text-decoration: underline;">Conclusions:</h4>
+ The experimental average difference of <span style="font-weight:
+ bold;">0.026</span>
+ Delta E76 shown above provides evidence that despite using a
+ completely
+ different instrument driver to that supplied with the instrument,
+ the
+ ArgyllCMS Eye-One pro measurement values have comparable accuracy,
+ and
+ can be relied upon to match measurements made using the original
+ manufactures driver.<br>
+ <h4 style="text-decoration: underline;">Raw Data:</h4>
+ The raw data is available in this <a href="i1proDriver.xls">spread
+ sheet</a>.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
</html>
diff --git a/doc/iccgamut.html b/doc/iccgamut.html
index ead8f7c..e6fb097 100644
--- a/doc/iccgamut.html
+++ b/doc/iccgamut.html
@@ -16,8 +16,8 @@
in Lab or CIECAM02 Jab colorspace, and can also representing the
gamut as a X3DOM file.<br>
<br>
- See <a href="3dformat.html">3D Viewing
- Format</a> for switching to VRML or X3D output format.<br>
+ See <a href="3dformat.html">3D Viewing Format</a> for switching to
+ VRML or X3D output format.<br>
<h3>Usage<br>
</h3>
<small><span style="font-family: monospace;">iccgamut [-options] </span><i
@@ -29,6 +29,7 @@
+
Verbose</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-d
sres&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Surface resolution
@@ -36,6 +37,7 @@
<span style="font-family: monospace;">&nbsp;-w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
emit
+
X3DOM .x3d.html file as well as CGATS .gam file</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -45,11 +47,13 @@ Don't
+
add X3DOM axes or white/black point</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-k&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Add
+
X3DOM markers for prim. &amp; sec. "cusp" points</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-f
@@ -66,6 +70,7 @@ s
+
= saturation, a = absolute (default), d = profile default</span></small><small><span
style="font-family: monospace;"></span></small><br
style="font-family: monospace;">
@@ -81,6 +86,7 @@ r
+
= reverse (priority: monochrome &gt; matrix &gt; lut)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><span
style="font-family: monospace;">-p oride</span><span
@@ -104,6 +110,7 @@ either
+
an enumerated choice, or a series of parameters:value changes</span><br
style="font-family: monospace;">
<span style="font-family: monospace;"></span></small><small><span
@@ -117,6 +124,7 @@ either
+
&nbsp; pe - Print evaluation environment (CIE 116-1995)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -125,6 +133,7 @@ either
+
&nbsp; pc - Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
style="font-family: monospace;"></span><span style="font-family:
monospace;"></span><br style="font-family: monospace;">
@@ -135,6 +144,7 @@ either
+
&nbsp; &nbsp; mt - Monitor in typical work environment</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -144,6 +154,7 @@ either
+
&nbsp; mb - Monitor in bright work environment</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
@@ -173,6 +184,7 @@ s:surround&nbsp;&nbsp;
+
n = auto, a = average, m = dim, d = dark,</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -182,6 +194,7 @@ s:surround&nbsp;&nbsp;
+
&nbsp; &nbsp;&nbsp; c = transparency (default average)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -191,6 +204,7 @@ w:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Adapted white point as XYZ (default media white)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -200,6 +214,7 @@ w:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Adapted white point as x, y</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -209,6 +224,7 @@ a:adaptation
+
Adaptation luminance in cd.m^2 (default 50.0)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -219,6 +235,7 @@ Background
+
% of image luminance (default 20)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; l:imagewhite Image
white in cd.m^2 if surround = auto (default 250)</span></small><br
@@ -231,6 +248,7 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Flare light % of image luminance (default 0)<br>
</span></small>&nbsp;</span><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -241,6 +259,7 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
g:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare color as XYZ
(default media white)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -248,8 +267,11 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
g:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare color as
x, y<br>
+ &nbsp;-x pcent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Expand/compress gamut cylindrically by percent<br>
&nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Create
@@ -257,6 +279,7 @@ Create
+
special cube surface topology plot<br style="font-family:
monospace;">
</span><i style="font-family: monospace;">profile</i><span
@@ -356,6 +379,12 @@ Create
conditions, either by choosing a typical viewing environment, or
controlling particular viewing condition parameters.<br>
<br>
+ The <b>-x</b> parameter allows expanding or compressing the
+ resulting gamut in a cylindrical direction by the given percentage
+ :- i.e "-x 120" will expand by 20%. This may be useful for creating
+ a general compression gamut mapping by using such an expanded device
+ gamut as input to <a href="collink.html#g">collink -g or -G</a>.<br>
+ <br>
The <span style="font-weight: bold;">-s</span> flag creates a
special hyper-cube surface plot that is artificially colored. This
can be useful for identifying the topology of the black ink color
diff --git a/doc/iccgamutmapping.html b/doc/iccgamutmapping.html
index 8deab44..11994c1 100644
--- a/doc/iccgamutmapping.html
+++ b/doc/iccgamutmapping.html
@@ -10,13 +10,12 @@
<h3>How ICC profiles support different intents</h3>
cLUT (Color Lookup Table) based ICC profiles support multiple <span
style="font-weight: bold;">intents</span> by having a table for
- each
- intent. In a typical device cLUT profile, there are up to 6 cLUT's,
- three for input (AtoB tables, that convert from device space to PCS
- (Profile connection space)), and three for output (BtoA tables, that
- convert from PCS to device space). The tables allow the use of
- different color transforms, each transform being tailored for a
- different effect:<br>
+ each intent. In a typical device cLUT profile, there are up to 6
+ cLUT's, three for input (AtoB tables, that convert from device space
+ to PCS (Profile connection space)), and three for output (BtoA
+ tables, that convert from PCS to device space). The tables allow the
+ use of different color transforms, each transform being tailored for
+ a different effect:<br>
<br>
AtoB0, BtoA0:&nbsp;&nbsp; Perceptual<br>
AtoB1, BtoA1:&nbsp;&nbsp; Colorimetric<br>
@@ -24,179 +23,144 @@
<br>
The colorimetric intent is meant to convey the exact device color
behaviour, without any gamut mapping. Typically it is used to store
- the
- devices behaviour (characterization), and is also used where exact
- color reproduction is required, such as for proofing. The
- Colorimetric
- tables double up for both relative colorimetric and
+ the devices behaviour (characterization), and is also used where
+ exact color reproduction is required, such as for proofing. The
+ Colorimetric tables double up for both relative colorimetric and
absolute colorimetric with the application of a white point
restoration.<br>
<br>
The Perceptual and Saturation tables are meant to contain gamut
- mapping
- combined with the device characterization. The allowance for this in
- both the AtoB direction, as well as the BtoA direction permits a
- profile to gamut map from the device gamut to some intermediate
- gamut,
- and then from the intermediate gamut to the device gamut.<br>
+ mapping combined with the device characterization. The allowance for
+ this in both the AtoB direction, as well as the BtoA direction
+ permits a profile to gamut map from the device gamut to some
+ intermediate gamut, and then from the intermediate gamut to the
+ device gamut.<br>
<br>
[Note that Shaper/Matrix profiles are always Colorimetric intent,
- since
- there is only a single transformation, and it does not have the
- necessary flexibility to accommodate gamut mapping.]<br>
+ since there is only a single transformation, and it does not have
+ the necessary flexibility to accommodate gamut mapping.]<br>
<h3>ICC Version 2 behaviour<br>
</h3>
Apart from defining the general purpose of the different tables, the
ICC Version 2 specification doesn't specify exactly how they are to
achieve this, so it is up to the profile maker to make a choice in
- this
- regard. There is no common gamut boundary specified for the PCS, and
- such an approach limits the achievable intents in any case (see ICC
- Version 4 behaviour for an explanation why).<br>
+ this regard. There is no common gamut boundary specified for the
+ PCS, and such an approach limits the achievable intents in any case
+ (see ICC Version 4 behaviour for an explanation why).<br>
<br>
What I've chosen to do with Argyll profiles, is to make all the AtoB
tables the same as colorimetric. This means that the conversion used
for the source profile is always colorimetric, and also means that
- the
- source gamut seen by the destination profile is the source
- colorspace
- gamut. This means that the gamut mapping is done solely in the BtoA
- tables,
- and that their task is to map the source colorspace gamut to the
- destination colorspace gamut. So to construct the perceptual and
- saturation intent mapping tables, a source profile or source gamut
- needs to be specified, so that a gamut mapping can be constructed.<br>
+ the source gamut seen by the destination profile is the source
+ colorspace gamut. This means that the gamut mapping is done solely
+ in the BtoA tables, and that their task is to map the source
+ colorspace gamut to the destination colorspace gamut. So to
+ construct the perceptual and saturation intent mapping tables, a
+ source profile or source gamut needs to be specified, so that a
+ gamut mapping can be constructed.<br>
<br>
The advantages of this approach is that the behaviour is precisely
defined, a full range of gamut mapping options is available, and
compatibility with matrix profiles (which do not have gamut mapping
transforms) and other foreign profiles can be assured, by simply
- using
- such profiles as colorimetric sources. The main disadvantage is that
- the gamut mapping will only operate exactly as intended when the
- profile is linked with the source profile it was setup for. This is
- really a fundamental limitation of the idea of having pre-computed
- gamut mapping color transforms, that the ICC profile format was
- intended to support.<br>
+ using such profiles as colorimetric sources. The main disadvantage
+ is that the gamut mapping will only operate exactly as intended when
+ the profile is linked with the source profile it was setup for. This
+ is really a fundamental limitation of the idea of having
+ pre-computed gamut mapping color transforms, that the ICC profile
+ format was intended to support.<br>
<br>
Some non-Argyll profile have gamut mapping transforms in their
Perceptual and Saturation A2B tables, and this means that the
- apparent
- gamut of a source through these tables may be different to the
- actual
- device gamut. To accommodate using these profiles with CMM's (Color
- Management Modules) that do not permit the separate choice of intent
- tables for the source and destination profiles, Argyll will by
- default
- use the gamut defined by the source profile perceptual table to
- create the gamut mapping of the destination perceptual table, and
- the
- source saturation table to make the destination saturation table.
- Note
- that this can affect the exact nature of the gamut mapping, the
- distortion of the source gamut changing the apparent relationship
- between it and the destination gamut - see "ICC Version 4 behavior"
- for
- an illustration of the kind of changes this causes. [This default
- can
- be overridden though using the colprof -nP and -nS flags.]<br>
+ apparent gamut of a source through these tables may be different to
+ the actual device gamut. To accommodate using these profiles with
+ CMM's (Color Management Modules) that do not permit the separate
+ choice of intent tables for the source and destination profiles,
+ Argyll will by default use the gamut defined by the source profile
+ perceptual table to create the gamut mapping of the destination
+ perceptual table, and the source saturation table to make the
+ destination saturation table. Note that this can affect the exact
+ nature of the gamut mapping, the distortion of the source gamut
+ changing the apparent relationship between it and the destination
+ gamut - see "ICC Version 4 behavior" for an illustration of the kind
+ of changes this causes. [This default can be overridden though using
+ the colprof -nP and -nS flags.]<br>
<h3>ICC Version 4 behaviour</h3>
(Note that Argyll does not currently support ICC V4)<br>
<br>
- By default, ICC Version 4 profile operates similarly to the ICC
- V2 profile in regard to gamut mapping, with the exception that a
+ By default, ICC Version 4 profile operates similarly to the ICC V2
+ profile in regard to gamut mapping, with the exception that a
minimally specified reference medium and reference viewing
conditions are introduced for perceptual (and presumably saturation)
tables, allowing at least the luminance range to have a well defined
behavior when mixing and matching the perceptual A2B and B2A tables
- of different profiles. A slight adjustment was made to
- the permitted tag contents, to allow things like Display profiles to
- contain the full range of AtoB and BtoA tables, so that they could
- also
- be gamut mapped. An optional part of ICCV4, introduces a more
- comprehensively specified <span style="font-weight: bold;">Profile
- Reference Medium Gamut</span>
- (PRMG) as an
- intermediate gamut boundary between the source colorspace, and the
- destination colorspace. If this option is used, then an additional
- tag
- in the ICCV4 profile indicates that this is the case. This then
- solves
- the problem of the gamut mapping having to know the source and
- destination gamuts to operate. Instead, the gamut mapping is split
- into
- two parts, the first where the source gamut to RMG is done by the
- AtoB
- tables, and then the RMG to destination gamut is done by the BtoA
- tables. Profiles can therefore be mix and matches, while retaining
- true
- gamut mapping.<br>
+ of different profiles. A slight adjustment was made to the permitted
+ tag contents, to allow things like Display profiles to contain the
+ full range of AtoB and BtoA tables, so that they could also be gamut
+ mapped. An optional part of ICCV4, introduces a more comprehensively
+ specified <span style="font-weight: bold;">Profile Reference Medium
+ Gamut</span> (PRMG) as an intermediate gamut boundary between the
+ source colorspace, and the destination colorspace. If this option is
+ used, then an additional tag in the ICCV4 profile indicates that
+ this is the case. This then solves the problem of the gamut mapping
+ having to know the source and destination gamuts to operate.
+ Instead, the gamut mapping is split into two parts, the first where
+ the source gamut to RMG is done by the AtoB tables, and then the RMG
+ to destination gamut is done by the BtoA tables. Profiles can
+ therefore be mix and matches, while retaining true gamut mapping.<br>
<br>
This approach has a number of drawbacks though. One is that the
- colors
- get gamut mapped twice. Gamut mapping is sometimes not very precise,
- and the geometry of the transforms may not cancel out, especially
- since
- different profile vendors may choose different algorithms in their
- gamut mapping. By "cancel out", I mean that even if you were linking
- the same source colorspace to the same destination colorspace, the
- gamut may be expanded (say) in the process of mapping to the PRMG,
- and
- then compressed again in mapping from the RMG to the device space,
- and
- these expansions and compressions may not quite match. Given that
- the
- PRMG is a relatively large gamut, larger than many real devices
- actual
+ colors get gamut mapped twice. Gamut mapping is sometimes not very
+ precise, and the geometry of the transforms may not cancel out,
+ especially since different profile vendors may choose different
+ algorithms in their gamut mapping. By "cancel out", I mean that even
+ if you were linking the same source colorspace to the same
+ destination colorspace, the gamut may be expanded (say) in the
+ process of mapping to the PRMG, and then compressed again in mapping
+ from the RMG to the device space, and these expansions and
+ compressions may not quite match. Given that the PRMG is a
+ relatively large gamut, larger than many real devices actual
behavior, this sort of expansion and re-compression will be the
- normal
- thing.<br>
+ normal thing.<br>
<br>
The chief drawback, is that only one (non colorimetric) intent can
really be supported, that of saturation. <br>
<br>
The typically expected behavior of perceptual intent gamut mapping,
- is
- to
- compress any areas of the source gamut that lie outside the
- destination
- gamut, but for areas that fall within the destination gamut, change
- them as little as possible, consistent with keeping smooth and
- proportional with respect to the compressed colors. This preserves
- the
- source "look" as much as
- possible, while ensuring that out of gamut colors are smoothly
- brought
- within the destination gamut.<br>
+ is to compress any areas of the source gamut that lie outside the
+ destination gamut, but for areas that fall within the destination
+ gamut, change them as little as possible, consistent with keeping
+ smooth and proportional with respect to the compressed colors. This
+ preserves the source "look" as much as possible, while ensuring that
+ out of gamut colors are smoothly brought within the destination
+ gamut.<br>
<br>
Typical behavior of a saturation intent, is (at least), to not only
compress out of gamut source colors to fit within the destination,
- but
- to expand any source boundary that falls within the destination
- gamut
- outwards match the destination gamut. Some practical saturation
- gamut
- mappings may go further than this, and expand a little beyond the
- destination gamut to ensure fully saturated boundary colors, and
- also
- enhance the saturation of all colors mapped through it.<br>
- <br>
- &nbsp;By mapping the source gamut to
- the RMG in the A2B, all information about what areas of the source
- gamut are
- inside or outside of the destination gamut are lost, so the
- destination
- gamut mapping can not known which colors may be left unchanged, and
- which really need compressing. All it can do is map the RMG to match
- the destination gamut,
- thereby effecting a saturation style intent. <br>
- <br>
- Once again, this is a fundamental limitation of using pre-computed
- gamut mappings. The only effective way of overcoming such
- limitations
- is to move to a more active color management architecture, in which
- gamut mappings are computed at link time, to accommodate the actual
- source and destination gamuts.<br>
+ but to expand any source boundary that falls within the destination
+ gamut outwards match the destination gamut. Some practical
+ saturation gamut mappings may go further than this, and expand a
+ little beyond the destination gamut to ensure fully saturated
+ boundary colors, and also enhance the saturation of all colors
+ mapped through it.<br>
+ <br>
+ &nbsp;By mapping the source gamut to the RMG in the A2B, all
+ information about what areas of the source gamut are inside or
+ outside of the destination gamut are lost, so the destination gamut
+ mapping can not known which colors may be left unchanged, and which
+ really need compressing. All it can do is map the RMG to match the
+ destination gamut, thereby effecting a saturation style intent. <br>
+ <br>
+ If the source was not expanded out to fill the RMG in some area by
+ the A2B, then the resulting output will be over compressed and end
+ up looking dull, because the B2A table has no choice but assume that
+ there may be colors that do fill the RMG.<br>
+ <br>
+ Once again, this is all a fundamental limitation of using
+ pre-computed gamut mappings. The only effective way of overcoming
+ such limitations is to move to a more active color management
+ architecture, in which gamut mappings are computed at link time, to
+ accommodate the actual source and destination gamuts.<br>
<br>
<br>
<img alt="Illustration of perceptual and saturation gamut mapping."
diff --git a/doc/illumread.html b/doc/illumread.html
index 3ee7aa5..697f772 100644
--- a/doc/illumread.html
+++ b/doc/illumread.html
@@ -1,309 +1,337 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>illumread</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- </head>
- <body>
- <h2><b>spectro/illumread</b></h2>
- <h3>Summary</h3>
- Use an instrument or instruments to measure an illuminant spectrum,
- including estimate its Ultra Violet content. A combination of direct
- illumination readings and readings from a piece of paper having some
- FWA content are used for this. (If the UV content is not needed, or
- a suitable instrument is not available, then <a
- href="spotread.html">spotread</a> should be used instead.)<br>
- <h3>Usage Summary</h3>
- <small><span style="font-family: monospace;">illumread [-options]
- illuminant.sp</span><br style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#v">-v</a><span
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>illumread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/illumread</b></h2>
+ <h3>Summary</h3>
+ Use an instrument or instruments to measure an illuminant spectrum,
+ including estimate its Ultra Violet content. A combination of direct
+ illumination readings and readings from a piece of paper having some
+ FWA content are used for this. (If the UV content is not needed, or
+ a suitable instrument is not available, then <a
+ href="spotread.html">spotread</a> should be used instead.)<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">illumread [-options]
+ illuminant.sp</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
- &nbsp; &nbsp; Verbose mode</span><span style="font-family:
- monospace;"></span></small><small><span style="font-family:
- monospace;"></span></small><br style="font-family: monospace;">
- <small><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#S">-S</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp; &nbsp; &nbsp; Plot the readings in a graph window.</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#c">-c comport</a><span
+
+
+
+ &nbsp; &nbsp; Verbose mode</span><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;"></span></small><br style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#S">-S</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; &nbsp; Plot the readings in a graph window.</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c comport</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Set
- COM port, 1..4 (default 1)</span><span style="font-family:
- monospace;"></span><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></small><small><span
- style="font-family: monospace;"></span></small><font size="-1"><span
- style="font-family: monospace;"></span></font><font size="-1"><span
- style="font-family: monospace;"><br>
- </span></font><font size="-1"><span style="font-family:
+
+
+
+ COM port, 1..4 (default 1)</span><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;"></span></small><font size="-1"><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Disable
- initial calibration of instrument</span></font> if possible<br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#H">-H</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode
- (if available)<br>
+
+
+
+ initial calibration of instrument</span></font> if possible<br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#H">-H</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode
+ (if available)<br>
<font size="-1">&nbsp;<a href="#Yr">-Y r</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Set refresh measurement mode</font><br>
- </span></font><font size="-1"><span style="font-family:
+
+
+
+ Set refresh measurement mode</font><br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
- serial port flow control: n = none, h = HW, x = Xon/Xoff</span></font><br>
- <small><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#T">-T</a><span
- style="font-family: monospace;">
+
+
+
+ serial port flow control: n = none, h = HW, x = Xon/Xoff</span></font><br>
+ <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#T">-T</a><span
+ style="font-family: monospace;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Test mode - restore &amp; save measurements to<br>
+
+
+
+ Test mode - restore &amp; save measurements to<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- *_i.sp, *_r.sp, *_p.sp, *_mpir.sp, *_cpir.sp files<br>
- </span></small> <small><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#D">-D [level]</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Print debug diagnostics to stderr</span></small><br>
- &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+
+
+
+ *_i.sp, *_r.sp, *_p.sp, *_mpir.sp, *_cpir.sp files<br>
+ </span></small> <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D [level]</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Print debug diagnostics to stderr</span></small><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
href="#file"><span style="font-style: italic;">illuminant.sp</span></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
File
- to save measurement to<br style="font-family: monospace;">
- </span></font><small><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></small><br>
- <h3>Usage Details and Discussion</h3>
- <b>illumread</b> uses a suitable instrument to read an illuminant
- spectrum, and uses an indirect method to estimate the Ultra Violet
- content of the illuminant, so as to provide better accuracy with <a
- href="FWA.html">FWA compensation</a>. An instrument or combination
- of instruments capable of spectral measurement of both emissive
- measurement and reflective measurement without a U.V. filter is
- required for this.<br>
- <br>
- <a name="v"></a>The <b>-v</b> flag causes extra information to be
- printed out during chartread operation.<br>
- <br>
- <a name="S"></a>The <b>-S</b> flag enables the plotting of the
- spectral reflectance/transmittance values. You must select the plot
- window and strike a key in it to continue with another measurement.<br>
- <br>
- <a name="c"></a> The instrument is assumed to communicate through a
- USB or serial communication port, and the initial port can be
- selected with the <b>-c</b> option, if the instrument is not
- connected to the first port. If you invoke <span
- style="font-weight: bold;">illumread</span> so as to display the
- usage information (i.e. "illumread -?" or "illumread --"), then the
- discovered USB and serial ports will be listed. On UNIX/Linux, a
- list of all possible serial ports are shown, but not all of them may
- actually be present on your system.<br>
- <br>
- <a name="N"></a><span style="font-weight: bold;">-N</span> Any
- instrument that requires regular calibration will ask for
- calibration on initial start-up. Sometimes this can be awkward if
- the instrument is being mounted in some sort of measuring jig, or
- annoying if several sets of readings are being taken in quick
- succession. The -<span style="font-weight: bold;">N</span>
- suppresses this initial calibration if a valid and not timed out
- previous calibration is recorded in the instrument or on the host
- computer. It is advisable to only use this option on the second and
- subsequent measurements in a single session.<br>
- <br>
- <a name="H"></a> The -<span style="font-weight: bold;">H</span>
- option turns on high resolution spectral mode, if the instrument
- supports it. See <a href="instruments.html">Operation of particular
- instruments</a> for more details.<br>
- <br>
- <a name="Yr"></a> The -<span style="font-weight: bold;">Y r</span>
- option turns on refresh mode measurement, if the instrument supports
- it. This may improve the repeatability of measurements of
- illuminants that have a repetitive flicker.<br>
- <br>
- <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
- parameter overrides the default serial communications flow control
- setting. The value <span style="font-weight: bold;">n</span> turns
- all flow control off, <span style="font-weight: bold;">h</span>
- sets hardware handshaking, and <span style="font-weight: bold;">x</span>
- sets Xon/Xoff handshaking. This commend may be useful in workaround
- serial communications issues with some systems and cables. <br>
- <br>
- <a name="T"></a>The <b>-T</b> flag invokes the test mode. In test
- mode the three measurements are saved to files <i>illuminant</i><i>_i.sp</i>
- (Illuminant spectrum), <i>illuminant</i><i>_r.sp</i> (Illuminant
- off paper spectrum), and <i>illuminant_p.sp (</i>Instrument
- measured paper reflectance spectrum), and these will be loaded if
- discovered, allowing a replay of the calculation without requiring
- any measurement. In addition, two diagnostic files <i>illuminant</i><i>_mpir.sp</i>
+
+
+
+ to save measurement to<br style="font-family: monospace;">
+ </span></font><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><br>
+ <h3>Usage Details and Discussion</h3>
+ <b>illumread</b> uses a suitable instrument to read an illuminant
+ spectrum, and uses an indirect method to estimate the Ultra Violet
+ content of the illuminant, so as to provide better accuracy with <a
+ href="FWA.html">FWA compensation</a>. An instrument or combination
+ of instruments capable of spectral measurement of both emissive
+ measurement and reflective measurement without a U.V. filter is
+ required for this.<br>
+ <br>
+ <a name="v"></a>The <b>-v</b> flag causes extra information to be
+ printed out during chartread operation.<br>
+ <br>
+ <a name="S"></a>The <b>-S</b> flag enables the plotting of the
+ spectral reflectance/transmittance values. You must select the plot
+ window and strike a key in it to continue with another measurement.<br>
+ <br>
+ <a name="c"></a> The instrument is assumed to communicate through a
+ USB or serial communication port, and the initial port can be
+ selected with the <b>-c</b> option, if the instrument is not
+ connected to the first port. If you invoke <span
+ style="font-weight: bold;">illumread</span> so as to display the
+ usage information (i.e. "illumread -?" or "illumread --"), then the
+ discovered USB and serial ports will be listed. On UNIX/Linux, a
+ list of all possible serial ports are shown, but not all of them may
+ actually be present on your system.<br>
+ <br>
+ <a name="N"></a><span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it. See <a href="instruments.html">Operation of particular
+ instruments</a> for more details.<br>
+ <br>
+ <a name="Yr"></a> The -<span style="font-weight: bold;">Y r</span>
+ option turns on refresh mode measurement, if the instrument supports
+ it. This may improve the repeatability of measurements of
+ illuminants that have a repetitive flicker.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="T"></a>The <b>-T</b> flag invokes the test mode. In test
+ mode the three measurements are saved to files <i>illuminant</i><i>_i.sp</i>
+ (Illuminant spectrum), <i>illuminant</i><i>_r.sp</i> (Illuminant
+ off paper spectrum), and <i>illuminant_p.sp (</i>Instrument
+ measured paper reflectance spectrum), and these will be loaded if
+ discovered, allowing a replay of the calculation without requiring
+ any measurement. In addition, two diagnostic files <i>illuminant</i><i>_mpir.sp</i>
(Measured paper under illuminant spectrum) and <i>illuminant</i><i>_cpir.sp
- (</i>Computed paper under illuminant spectrum) will be saved.<br>
- <br>
- <a name="D"></a>The <b>-D</b> flag causes communications and other
- instrument diagnostics to be printed to stdout. A level can be set
- between 1 .. 9, that may give progressively more verbose
- information, depending on the instrument. This can be useful in
- tracking down why an instrument can't connect.<br>
- <br>
- <a name="file"></a>The <span style="font-weight: bold; font-style:
- italic;">illuminant.sp</span> is the name of the file to save the
- resulting illuminant spectrum to. The format used is <a
- href="File_Formats.html#.sp">.sp</a>.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- Unlike the other measurement utilities, <span style="font-weight:
- bold;">illumread</span> doesn't connect to the instrument until it
- is about to make a measurement. This allows for the possibility of
- using a different instrument for each measurement.<br>
- <br>
- It will display a menu:<br>
- <br>
- Press 1 .. 6<br>
- 1) Measure direct illuminant<br>
- 2) Measure illuminant reflected from paper<br>
- 3) Measure paper<br>
- 4) Select another instrument, Currently 1 'usb:/bus4/dev2/
- (GretagMacbeth i1 Pro)'<br>
- 5) Compute illuminant spectrum, average result with 0 previous
- readings &amp; save it<br>
- 6) Compute illuminant spectrum from this reading &amp; save result<br>
- 7) Exit<br>
- <br>
- There are three measurements to be made, after which the illuminant
- can be computed and saved. Before each measurement, the instrument
- may need calibrating.<br>
- <br>
- The first measurement needs a spectral instrument capable of reading
- in an ambient or emissive mode. For instance, a Spectrolino, Eye-One
- Pro or ColorMunki would be suitable instruments.<br>
- <br>
- The second measurement needs a spectral instrument capable of
- reading in an projector or emissive mode. For instance, a
- Spectrolino, Eye-One Pro or ColorMunki would be suitable
- instruments.<br>
- <br>
- The third measurement needs a spectral instrument capable of reading
- in reflective mode with UV included. For instance, a Spectrolino,
- Eye-One Pro, DTP20, DTP22 or&nbsp; DTP41 would be suitable
- instruments, as long as they are not fitted with UV filters.<br>
- <br>
- To be able to estimate the level of Ultra Violet (UV) light in the
- illuminant, a reasonable sized piece of white paper needs to be
- used. The paper should have some noticeable level of FWA
- (Fluorescent Whitener Additive, or Optical Brightening Agents) in
- it, so that it responds to UV light. A piece of cheap copier paper
- is ideal, since cheap paper is typically whitened with large amounts
- of FWA. If the paper is thin (less than 160 gsm) then two or three
- sheets should be used to prevent any background showing through. If
- the intention is to use the illuminant spectrum for proofing to a
- particular paper, then it's best to use the intended paper for this
- purpose.<br>
- <br>
- The first measurement <span style="font-weight: bold;">1)</span>,
- is to use either the ambient or emissive measurement mode to measure
- the illumination directly.<br>
- <br>
- <div style="margin-left: 40px;">If the instrument supports an
- ambient measurement capability, then it will be used. If the
- insrument does not have an ambient mode, then an emissive
- measurement mode can be used, although typically many illuminants
- are too bright to directly point the instrument at. A work-around
- is to reflect the illuminant from a spectrally flat white surface.
- A good candidate for this is a piece of white, fine textured
- polystyrene foam. [The suitability of a reflector can be checked
- using <span style="font-weight: bold;">spotread -S</span> to
- check that the reflection characteristic is close to flat.]<br>
- <br>
- <img style="width: 228px; height: 300px;" alt="Measuring Ambient"
- src="illumread_1.jpg"><img style="width: 141px; height: 282px;"
- alt="Measuring Ambient" src="illumread_2.jpg">&nbsp; <img
- style="width: 226px; height: 282px;" alt="Measuring Ambient"
- src="illumread_3.jpg"><br>
- </div>
- <br>
- The second measurement <span style="font-weight: bold;">2)</span>,
- is to measure the illuminant after it has reflected from the paper.<br>
- <br>
- <div style="margin-left: 40px;">This is done by placing the paper
- such that it is uniformly illuminated with reasonable brightness,
- and then placing the instrument so that it receives the reflected
- light from the paper. This is typically achieved by placing the
- instrument close to the paper at about 45º, so that it's aperture
- has a clear view of the illuminated paper, but avoiding shadowing
- the region that is in view. <br>
- <br>
- <img style="width: 219px; height: 261px;" alt="Measuring via
- Paper" src="illumread_5.jpg"><img style="width: 252px; height:
- 259px;" alt="Measuring via Paper" src="illumread_4.jpg"><br>
- </div>
- <br>
- The third measurement <span style="font-weight: bold;">3)</span>,
- is to measure the paper directly using the instrument reflective
- mode measurement.<br>
- <div style="margin-left: 40px;"><img style="width: 186px; height:
- 162px;" alt="Measuring Paper" src="illumread_6.jpg"><br>
- </div>
- If a different instrument is needed, use <span style="font-weight:
- bold;">4)</span> to select from the available instruments attached
- to your computer.<br>
- <br>
- Once these three measurements have been made, then the illuminant
- readings spectrum can be computed and save using <span
- style="font-weight: bold;">6)</span>, or a series of readings can
- be made with each reading being averages with the previous readings
- before saving it by using <span style="font-weight: bold;">5)</span>.
- Note that the averaged readings will be weighted by their absolute
- intensities, and that while the direct and indirect illumination
- needs measuring for each reading, the same paper measurement can be
- used each time.<br>
- <br>
- If plotting is enabled, a plot of the measured (black) and with
- estimated UV (red) is plotted. This is followed by a plot showing
- measured paper reflectance (black) and the FWA calculated paper
- reflectance (red).<br>
- <br>
- <br>
- Illumread can then be terminated using <span style="font-weight:
- bold;">7)</span>.<br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+
+
+ (</i>Computed paper under illuminant spectrum) will be saved.<br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="file"></a>The <span style="font-weight: bold; font-style:
+ italic;">illuminant.sp</span> is the name of the file to save the
+ resulting illuminant spectrum to. The format used is <a
+ href="File_Formats.html#.sp">.sp</a>.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ Unlike the other measurement utilities, <span style="font-weight:
+ bold;">illumread</span> doesn't connect to the instrument until it
+ is about to make a measurement. This allows for the possibility of
+ using a different instrument for each measurement.<br>
+ <br>
+ It will display a menu:<br>
+ <br>
+ Press 1 .. 6<br>
+ 1) Measure direct illuminant<br>
+ 2) Measure illuminant reflected from paper<br>
+ 3) Measure paper<br>
+ 4) Select another instrument, Currently 1 'usb:/bus4/dev2/
+ (GretagMacbeth i1 Pro)'<br>
+ 5) Compute illuminant spectrum, average result with 0 previous
+ readings &amp; save it<br>
+ 6) Compute illuminant spectrum from this reading &amp; save result<br>
+ 7) Exit<br>
+ <br>
+ There are three measurements to be made, after which the illuminant
+ can be computed and saved. Before each measurement, the instrument
+ may need calibrating.<br>
+ <br>
+ The first measurement needs a spectral instrument capable of reading
+ in an ambient or emissive mode. For instance, a Spectrolino, Eye-One
+ Pro or ColorMunki would be suitable instruments.<br>
+ <br>
+ The second measurement needs a spectral instrument capable of
+ reading in an projector or emissive mode. For instance, a
+ Spectrolino, Eye-One Pro or ColorMunki would be suitable
+ instruments.<br>
+ <br>
+ The third measurement needs a spectral instrument capable of reading
+ in reflective mode with UV included. For instance, a Spectrolino,
+ Eye-One Pro, DTP20, DTP22 or&nbsp; DTP41 would be suitable
+ instruments, as long as they are not fitted with UV filters.<br>
+ <br>
+ To be able to estimate the level of Ultra Violet (UV) light in the
+ illuminant, a reasonable sized piece of white paper needs to be
+ used. The paper should have some noticeable level of FWA
+ (Fluorescent Whitener Additive, or Optical Brightening Agents) in
+ it, so that it responds to UV light. A piece of cheap copier paper
+ is ideal, since cheap paper is typically whitened with large amounts
+ of FWA. If the paper is thin (less than 160 gsm) then two or three
+ sheets should be used to prevent any background showing through. If
+ the intention is to use the illuminant spectrum for proofing to a
+ particular paper, then it's best to use the intended paper for this
+ purpose.<br>
+ <br>
+ The first measurement <span style="font-weight: bold;">1)</span>,
+ is to use either the ambient or emissive measurement mode to measure
+ the illumination directly.<br>
+ <br>
+ <div style="margin-left: 40px;">If the instrument supports an
+ ambient measurement capability, then it will be used. If the
+ insrument does not have an ambient mode, then an emissive
+ measurement mode can be used, although typically many illuminants
+ are too bright to directly point the instrument at. A work-around
+ is to reflect the illuminant from a spectrally flat white surface.
+ A good candidate for this is a piece of white, fine textured
+ polystyrene foam. [The suitability of a reflector can be checked
+ using <span style="font-weight: bold;">spotread -S</span> to
+ check that the reflection characteristic is close to flat.]<br>
+ <br>
+ <img alt="Measuring Ambient" src="illumread_1.jpg" width="143"
+ height="272"> <img style="width: 141px; height: 282px;"
+ alt="Measuring Ambient" src="illumread_2.jpg">&nbsp; <img
+ style="width: 226px; height: 282px;" alt="Measuring Ambient"
+ src="illumread_3.jpg"><br>
+ </div>
+ <br>
+ The second measurement <span style="font-weight: bold;">2)</span>,
+ is to measure the illuminant after it has reflected from the paper.<br>
+ <br>
+ <div style="margin-left: 40px;">This is done by placing the paper
+ such that it is uniformly illuminated with reasonable brightness,
+ and then placing the instrument so that it receives the reflected
+ light from the paper. This is typically achieved by placing the
+ instrument close to the paper at about 45º, so that it's aperture
+ has a clear view of the illuminated paper, but avoiding shadowing
+ the region that is in view, and also avoiding measuring specular
+ reflection if the paper is glossy.<br>
+ <br>
+ <img style="width: 219px; height: 261px;" alt="Measuring via
+ Paper" src="illumread_5.jpg"><img style="width: 252px; height:
+ 259px;" alt="Measuring via Paper" src="illumread_4.jpg"><br>
+ </div>
+ <br>
+ The third measurement <span style="font-weight: bold;">3)</span>,
+ is to measure the paper directly using the instrument reflective
+ mode measurement.<br>
+ <div style="margin-left: 40px;"><img style="width: 186px; height:
+ 162px;" alt="Measuring Paper" src="illumread_6.jpg"><br>
+ </div>
+ If a different instrument is needed, use <span style="font-weight:
+ bold;">4)</span> to select from the available instruments attached
+ to your computer.<br>
+ <br>
+ Once these three measurements have been made, then the illuminant
+ readings spectrum can be computed and save using <span
+ style="font-weight: bold;">6)</span>, or a series of readings can
+ be made with each reading being averages with the previous readings
+ before saving it by using <span style="font-weight: bold;">5)</span>.
+ Note that the averaged readings will be weighted by their absolute
+ intensities, and that while the direct and indirect illumination
+ needs measuring for each reading, the same paper measurement can be
+ used each time.<br>
+ <br>
+ If plotting is enabled, a plot of the measured (black) and with
+ estimated UV (red) is plotted. This is followed by a plot showing
+ measured paper reflectance (black) and the FWA calculated paper
+ reflectance (red).<br>
+ <br>
+ <br>
+ Illumread can then be terminated using <span style="font-weight:
+ bold;">7)</span>.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/instruments.html b/doc/instruments.html
index 1e287fc..d7f5d30 100644
--- a/doc/instruments.html
+++ b/doc/instruments.html
@@ -1,28 +1,28 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>Operation of particular instruments</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- </head>
- <body>
- <h2><u>Operation of particular instruments</u></h2>
- <span style="font-weight: bold;">Please note that instruments are
- being driven by ArgyllCMS drivers, and that any problems or
- queries regarding instrument<br>
- operation </span><span style="font-weight: bold;">should be
- directed to the Argyll's author(s) or the Argyll mailing list, and
- not to any</span> <span style="font-weight: bold;">other party.</span><span
- style="font-weight: bold;"></span><br>
- <br>
- The following instruments are directly supported:<br>
- (Please <span style="font-weight: bold;">note</span> the <a
- href="Installing.html">installation instructions</a> for each
- platform - they contain important information for getting your
- instruments working.)<br>
- <br>
- JETI:<br>
- <br>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Operation of particular instruments</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ </head>
+ <body>
+ <h2><u>Operation of particular instruments</u></h2>
+ <span style="font-weight: bold;">Please note that instruments are
+ being driven by ArgyllCMS drivers, and that any problems or
+ queries regarding instrument<br>
+ operation </span><span style="font-weight: bold;">should be
+ directed to the Argyll's author(s) or the Argyll mailing list, and
+ not to any</span> <span style="font-weight: bold;">other party.</span><span
+ style="font-weight: bold;"></span><br>
+ <br>
+ The following instruments are directly supported:<br>
+ (Please <span style="font-weight: bold;">note</span> the <a
+ href="Installing.html">installation instructions</a> for each
+ platform - they contain important information for getting your
+ instruments working.)<br>
+ <br>
+ JETI:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="#specbos">specbos 1211 &amp; 1201</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -49,10 +49,27 @@
- - Tele-Spectro-Radiometer<br>
- <br>
- Image Engineering:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ - Tele-Spectro-Radiometer<br>
+ &nbsp;&nbsp;&nbsp; <a href="#spectraval">spectraval 1511&amp; 1501</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+ &nbsp;&nbsp; - Tele-Spectro-Radiometer<br>
+ <br>
+ Image Engineering:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="#ex1">EX1</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -108,19 +125,30 @@
- - Tele-Spectro-Radiometer<br>
- <br>
- Klein:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="#k10a">K10-A</a>&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; - Display Colorimeter. Reported also to work with
- the K-1, K-8 and&nbsp; K-10<br>
- <br>
- X-Rite:<br>
- &nbsp;&nbsp;&nbsp; <a href="#DTP20">DTP20 "Pulse"</a>&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ - Tele-Spectro-Radiometer<br>
+ <br>
+ Klein:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="#k10a">K10-A</a>&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; - Display Colorimeter. Reported also to work with
+ the K-1, K-8 and&nbsp; K-10<br>
+ <br>
+ X-Rite:<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP20">DTP20 "Pulse"</a>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -169,7 +197,18 @@
- - "swipe" type reflective spectrometer, that can be used untethered.<br>
+
+
+
+
+
+
+
+
+
+
+
+ - "swipe" type reflective spectrometer, that can be used untethered.<br>
&nbsp;&nbsp;&nbsp; <a href="#DTP22">DTP22 Digital Swatchbook</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -218,7 +257,18 @@
- - spot type reflective spectrometer.<br>
+
+
+
+
+
+
+
+
+
+
+
+ - spot type reflective spectrometer.<br>
&nbsp;&nbsp;&nbsp; <a href="#DTP41">DTP41</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -267,9 +317,20 @@
- - spot and strip reading reflective spectrometer.<br>
- &nbsp;&nbsp;&nbsp; <a href="#DTP41">DTP41T</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ - spot and strip reading reflective spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP41">DTP41T</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -318,7 +379,18 @@
- - spot and strip reading reflective/transmissive spectrometer.<br>
+
+
+
+
+
+
+
+
+
+
+
+ - spot and strip reading reflective/transmissive spectrometer.<br>
&nbsp;&nbsp;&nbsp; <a href="#dtp51">DTP51</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -367,7 +439,18 @@
- - strip reading reflective colorimeter.<br>
+
+
+
+
+
+
+
+
+
+
+
+ - strip reading reflective colorimeter.<br>
&nbsp;&nbsp;&nbsp; <a href="#DTP92">DTP92</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -416,7 +499,18 @@
- - CRT display colorimeter.<br>
+
+
+
+
+
+
+
+
+
+
+
+ - CRT display colorimeter.<br>
&nbsp;&nbsp;&nbsp; <a href="#DTP94">DTP94</a> <font size="-1">"Optix
@@ -465,7 +559,18 @@
- XR"</font> or "Optix XR2" or "Optix Pro"- display colorimeter.<br>
+
+
+
+
+
+
+
+
+
+
+
+ XR"</font> or "Optix XR2" or "Optix Pro"- display colorimeter.<br>
<a href="#ColorMunki"><span style="text-decoration: underline;"></span></a>&nbsp;&nbsp;&nbsp;
@@ -514,61 +619,72 @@
- <a href="#ColorMunki"><span style="text-decoration: underline;">ColorMunki</span></a>
- Design or Photo&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - spot and "swipe"
- reflective/emissive spectrometer (UV cut only).<br>
- &nbsp;&nbsp;&nbsp; <a href="#i1d"><span style="text-decoration:
- underline;">ColorMunki</span></a> Create or Smile&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
- colorimeter. (Similar to an Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="#Huey">Lenovo W</a> &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - built in laptop
- Huey display colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="#i1d3">Eye-One Display 3</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; - i1 DisplayPro and ColorMunki Display<br>
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
- i1Display Pro, NEC SpectraSensor Pro,<br>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM and HP
- DreamColor&nbsp; i1d3 are also reported to work.]<br>
- &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
- "swipe" reflective/emissive spectrometer.<br>
- <br>
- Gretag-Macbeth (now X-Rite):<br>
- &nbsp; &nbsp; <a href="#sl">Spectrolino</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive
- spectrometer<br>
- &nbsp; &nbsp; <a href="#ss">SpectroScan</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive, XY table
- reflective spectrometer&nbsp; <br>
- &nbsp; &nbsp; <a href="#ss">SpectroScanT</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; - spot reflective/emissive/transmissive, XY
- table reflective spectrometer<br>
- &nbsp; &nbsp; <a href="#i1p">Eye-One Pro</a> "EFI ES-1000" &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" reflective/emissive
- spectrometer<br>
- &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive spectrometer<br>
- &nbsp;&nbsp;&nbsp; <a href="#i1d">Eye-One Display 1 or 2&nbsp; or
- LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
- colorimeter<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
- APS</a>&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ <a href="#ColorMunki"><span style="text-decoration: underline;">ColorMunki</span></a>
+ Design or Photo&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - spot and "swipe"
+ reflective/emissive spectrometer (UV cut only).<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d"><span style="text-decoration:
+ underline;">ColorMunki</span></a> Create or Smile&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter. (Similar to an Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#Huey">Lenovo W</a> &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - built in laptop
+ Huey display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d3">Eye-One Display 3</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; - i1 DisplayPro and ColorMunki Display<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
+ i1Display Pro, NEC SpectraSensor Pro,<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM and HP
+ DreamColor&nbsp; i1d3 are also reported to work.]<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
+ "swipe" reflective/emissive spectrometer.<br>
+ <br>
+ Gretag-Macbeth (now X-Rite):<br>
+ &nbsp; &nbsp; <a href="#sl">Spectrolino</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive
+ spectrometer<br>
+ &nbsp; &nbsp; <a href="#ss">SpectroScan</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive, XY table
+ reflective spectrometer&nbsp; <br>
+ &nbsp; &nbsp; <a href="#ss">SpectroScanT</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; - spot reflective/emissive/transmissive, XY
+ table reflective spectrometer<br>
+ &nbsp; &nbsp; <a href="#i1p">Eye-One Pro</a> "EFI ES-1000" &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" reflective/emissive
+ spectrometer<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive spectrometer<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d">Eye-One Display 1 or 2&nbsp; or
+ LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
+ APS</a>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -617,8 +733,19 @@
- - display colorimeter. (Treated as a Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="#i1d">CalMAN X2</a>
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d">CalMAN X2</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -667,17 +794,28 @@
- - display colorimeter. (Treated as a Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="#Huey">Huey</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter<br>
- <br>
- Sequel imaging (Now X-Rite):<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#mox">MonacoOPTIX</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Treated
- as an Eye-One Display 1)<br>
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#Huey">Huey</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter<br>
+ <br>
+ Sequel imaging (Now X-Rite):<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#mox">MonacoOPTIX</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Treated
+ as an Eye-One Display 1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -726,9 +864,21 @@
- [The Sequel Chroma 4 may also work.]<br>
- <br>
- Lacie Blue
+
+
+
+
+
+
+
+
+
+
+
+ [The Sequel Chroma 4 &amp; 5, and Sencore ColorPro V, IV &amp; III
+ also work.]<br>
+ <br>
+ Lacie Blue
Eye:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -777,14 +927,25 @@
- - see <a href="#i1d">Eye-One Display</a><br>
- <br>
- DataColor ColorVision:<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd2">Spyder 2</a> &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> firmware)<br>
+
+
+
+
+
+
+
+
+
+
+
+ - see <a href="#i1d">Eye-One Display</a><br>
+ <br>
+ DataColor ColorVision:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd2">Spyder 2</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> firmware)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -833,26 +994,37 @@
- [The Spyder 1 also seems to work.]<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd3">Spyder 3</a> &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd4">Spyder 4</a> &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> calibration
- data)<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd5">Spyder 5</a> &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> calibration
- data)<br>
- <br>
- Other:<br>
- &nbsp;&nbsp;&nbsp; <span class="titre"><a href="#HCFR">Colorimètre
+
+
+
+
+
+
+
+
+
+
+
+ [The Spyder 1 also seems to work.]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd3">Spyder 3</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd4">Spyder 4</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd5">Spyder 5</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ <br>
+ Other:<br>
+ &nbsp;&nbsp;&nbsp; <span class="titre"><a href="#HCFR">Colorimètre
HCFR</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -901,8 +1073,6 @@
- - display colorimeter<br>
- </span>&nbsp;&nbsp;&nbsp; <a href="#ColorHug">ColorHug</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -913,6 +1083,14 @@
+
+ - display colorimeter<br>
+ </span>&nbsp;&nbsp;&nbsp; <a href="#ColorHug">ColorHug</a> &amp;
+ ColorHug2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
@@ -941,287 +1119,303 @@
- - display colorimeter<span class="titre"></span><br>
- &nbsp;&nbsp;&nbsp; <a href="#SMCube">Palette/SwatchMate Cube</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- - reflective colorimeter<br>
- <br>
- Other instruments can be supported indirectly, since patch result
- files created by other packages can be imported into Argyll.<br>
- <span class="titre"><br>
- General information about:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="#strip">Strip reading instruments</a><br>
- </span>&nbsp;&nbsp;&nbsp; <a href="#xy">X-Y Table instruments</a><br>
- &nbsp;&nbsp;&nbsp; <a href="#spot">Spot reading instruments</a><br>
- <span style="font-weight: bold;"></span><br>
- <br>
- There is a <a href="ccmxs.html">list of contributed</a> <span
- style="font-weight: bold;">ccmx</span> (Colorimeter Correction
- Matrix) files.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h3><a name="strip"></a>Strip reading instruments</h3>
- When used with a <span style="font-weight: bold;">DT20</span>, <span
- style="font-weight: bold;">DTP41</span>, <span
- style="font-weight: bold;">DTP51</span>, <span
- style="font-weight: bold;">Eye-One Pro<span style="font-weight:
- bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
- strip reading instrument, chartread will first establish
- communications with the instrument, and then set it up ready to read
- the strips. The strips are labeled A to ZZ, and for each strip it
- will prompt:<br>
- <br>
- &nbsp;&nbsp;&nbsp; About to read strip XX&nbsp; :<br>
- <br>
- where XX is the strip label, and this is followed by the available
- options to navigate, read the strip, or finish. Note that the normal
- (forward) direction of strip reading is one that starts at the strip
- label.<br>
- <br>
- For the <span style="font-weight: bold;">DTP51</span> you should
- feed the strip into the instrument, and the microswitch will trigger
- the read.<br>
- <br>
- For the <span style="font-weight: bold;">DTP41</span> you should
- line the appropriate strip up in the machine, and press its button.<br>
- <br>
- For the <span style="font-weight: bold;">Eye-One Pro</span> you
- should set the guide to the appropriate strip, place the instrument
- <span style="text-decoration: underline;">ahead</span> of the first
- patch on blank paper, and then press and hold the instruments
- button. When you hear a beep from the computer, you can then move
- the instrument steadily over the patches, releasing the button after
- the instrument is past the last patch. Moving the instrument too
- fast or changing speeds may cause a mis-read, or a scan with few
- samples read per patch.<br>
- <br>
- For the <span style="font-weight: bold;">ColorMunki</span> with the
- default chart, the patches are the same width as the silver portion
- of body (white version), or the textured portion of the body (black
- version). Place aperture of the the instrument (located at its
- center) in the white space ahead of the first patch, and then press
- and hold the instruments button. When you hear a beep from the
- computer, you can then move the instrument steadily over the
- patches, releasing the button after the instrument is past the last
- patch. Moving the instrument too fast or changing speeds may cause a
- mis-read, or a scan with few samples read per patch. For the <span
- style="font-weight: bold;">high density</span> ColorMunki chart (<a
- href="printtarg.html#h">printtarg -h</a>), the patches are
- arranged so that three rows are exactly the width of the&nbsp; body
- of the instrument. If you are careful you can use this to guide the
- center of the instrument over each row, or you may prefer to use
- something like a plastic ruler to help guide the instrument.<br>
- <br>
- Using the <span style="font-weight: bold;">DTP20</span> or the <span
- style="font-weight: bold;">Eye-One Pro</span> or <span
- style="font-weight: bold;">ColorMunki</span> with a randomized
- chart layout, the strip may be scanned from either direction. If a
- randomized chart layout has not been used for the <span
- style="font-weight: bold;">Eye-One Pro</span> or <span
- style="font-weight: bold;">ColorMunki</span>, then the chart
- should only be read in the one direction (use <a
- href="chartread.html#B">chartread -B</a>).<br>
- <br>
- Note that you may have to check that system alert sounds are enabled
- and at a suitable volume to in order to hear the beep prompt. For
- the Eye-One Pro and ColorMunki, a second beep will sound after a
- successfully read strip, or a double beep will sound,&nbsp;
- indicating a failure or warning that needs attention. See also the
- note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
- <br>
- If the strip is read successfully there will be a single "success"
- beep, and the line will be followed with:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; : <br>
- &nbsp;&nbsp;&nbsp; Strip read OK<br>
- <br>
- If there is an error of some sort there will be a double "fail"
- beep, and a message will be issued, and you will be asked whether to
- abort the chart reading, or retry the<br>
- failed strip:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read strip XX&nbsp; : <br>
- &nbsp;&nbsp;&nbsp; Strip read failed due to misread (Not enough
- patches)<br>
- <br>
- &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
- <br>
- If you are unable to successfully read a strip after several
- retries, you can skip that strip using the <span
- style="font-weight: bold;">'n'</span> key, and save<br>
- the chart readings without that strip.<br>
- <br>
- If the strip is read successfully, but the patches values don't seem
- to be what is expected, you will get a double "fail" beep&nbsp; and
- the following type of warning:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
- &nbsp;&nbsp;&nbsp; (Warning) Seem to have read strip&nbsp; YY&nbsp;
- rather than&nbsp; XX !<br>
- &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
- retry, Esc, ^C or Q to give up:<br>
- <br>
- This could be because you have accidentally read the wrong strip (a
- common mistake), or it could be that the device response is so
- different from what is expected that warning is erroneous, or you
- may get a lot of these sorts of warnings if you are accidentally
- reading the wrong chart. You may also get this sort of warning if
- you are not using bi-direction reading (chartread -B), and read the
- strip from the wrong end.<br>
- If you are absolutely sure you lined up the correct strip, then hit
- return, otherwise line the appropriate strip up again, and hit some
- other key (ie. space).<br>
- Erroneous warnings are less likely if a previous profile for a
- device was given to <span style="font-weight: bold;">targen</span>
- to set more accurate expectations.<br>
- <br>
- You may also see the following type of warning:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
- &nbsp;&nbsp;&nbsp; (Warning) Patch error YY.YYY (&gt;35 not good,
- &gt;95 bad)<br>
- &nbsp;&nbsp; There is at least one patch with an very unexpected
- response!<br>
- &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
- retry, Esc, ^C or Q to give up:<br>
- <br>
- Similar to the previous warning, this indicates that while the right
- strip appears to have been read, one of the patch readings is quite
- different to what is expected. This may indicate an error of some
- sort (ie. damaged test chart, or bad instrument positioning), or may
- be erroneous if the actual device response is quite different to the
- expectation. Erroneous warnings are less likely if a previous
- profile for a device was given to <span style="font-weight: bold;">targen</span>
- to set more accurate expectations.<br>
- <br>
- You can also navigate the next strip to be read using the <span
- style="font-weight: bold;">'f'</span> key to move forward and the
- <span style="font-weight: bold;">'b'</span> keys<span
- style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
- to move backwards. The prompt will indicate whether this strip has
- already been read or not, or whether all strips have been read. You
- can also use <span style="font-weight: bold;">'n'</span> to move
- forward to the next unread strip. After each successful reading it
- will move forward to the next unread strip. When you are finished,
- use the <span style="font-weight: bold;">'d'</span> to indicate
- that you are done. You can choose to finish before all the strips
- are read, and the patches that have been read will be saved to the
- .ti3 file. This is useful if you are unable to read a particular
- strip successfully, or if you are unable to finish the chart in one
- session, and you can later <span style="text-decoration:
- underline;">resume</span> reading the chart by using the <span
- style="font-weight: bold;">chartread -r</span> flag. [You could
- resume reading the chart patch by patch using the <span
- style="font-weight: bold;">chartread -r -p</span> if you are
- unable to read a strip successfully.]<br>
- <br>
- When reading in patch by patch mode, there are a few additional
- navigation options, such as <span style="font-weight: bold;"><span
- style="font-weight: bold;">F</span></span> to move forward 10
- patches, <span style="font-weight: bold;">B</span> to move
- backwards 10 patches, and <span style="font-weight: bold;">g</span>
- to go to a specific patch.<br>
- <br>
- You can abort the whole process at any time by hitting Escape, and
- the readings will not be saved.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h3><a name="xy"></a>X-Y Table instruments</h3>
- When you are using an XY table type instrument, such as a Gretag <span
- style="font-weight: bold;">SpectroScan</span>, &nbsp;chartread
- will first establish communications with the instrument, and then
- set it up ready to read the chart. You will be prompted for each
- sheet with a message such as:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Please make sure that the white reference is in
- slot 1, then<br>
- &nbsp;&nbsp;&nbsp; place sheet 1 of 4 on table, then<br>
- &nbsp;&nbsp;&nbsp; hit return to continue, Esc to give up<br>
- <br>
- After hitting return you will be prompted to line up three squares
- on the sheet, one at a time:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Using the XY table controls, locate patch A1 with
- the sight,<br>
- &nbsp;&nbsp;&nbsp; then hit return to continue, Esc to give up<br>
- <br>
- On completing this, the instrument will commence reading each sheet.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h3><a name="spot"></a>Spot reading instruments</h3>
- When used with a <span style="font-weight: bold;">DT22</span> or <span
- style="font-weight: bold;">SpectroLino</span> or use the patch by
- patch reading mode (<span style="font-weight: bold;">chartread -p</span>)
- with the <span style="font-weight: bold;"></span> <span
- style="font-weight: bold;">Eye-One Pro<span style="font-weight:
- bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
- instrument, or use the external values mode (<span
- style="font-weight: bold;">chartread -x</span>), chartread will
- first establish communications with the instrument, and then set it
- up ready to read the patches. The patches are typically labeled by
- column A to ZZ, and row 1-999. Each patch will prompt:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read patch 'XX'&nbsp; :<br>
- <br>
- where XX is the patch label, and this is followed by the available
- options to navigate, read the strip, or finish.<br>
- <br>
- Place the instrument on the indicated patch, and trigger a reading
- using one of the available methods (typically using the instrument
- switch of pressing a key).<br>
- <br>
- There should be an audible prompt on a successful or failed reading.
- <br>
- <br>
- Note that you may have to check that system alert sounds are enabled
- and at a suitable volume to in order to hear the beep prompt. For
- the Eye-One Pro and ColorMunki, a second beep will sound after a
- successfully read strip, or a double beep will sound,&nbsp;
- indicating a failure or warning that needs attention. See also the
- note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
- <br>
- If the patch is read successfully, the line will be completed with:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read patch&nbsp; XX&nbsp; :<br>
- &nbsp;&nbsp;&nbsp; Patch read OK<br>
- <br>
- If there is an error of some sort, a message will be issued, and you
- will be asked whether to abort the chart reading, or retry the<br>
- failed patch:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read patch XX&nbsp; : read_strip
- returned 'Strip misread' (Bad reading)<br>
- <br>
- &nbsp;&nbsp;&nbsp; Strip read failed due to misread<br>
- &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
- <br>
- You can navigate the next patch to be read using the <span
- style="font-weight: bold;">'f'</span> key to move forward and the
- <span style="font-weight: bold;">'b'</span> keys<span
- style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
- to move backwards, while <span style="font-weight: bold;">'F'</span>
- and <span style="font-weight: bold;">'B'</span> will move forward
- and backwards by 10 patches. The prompt will indicate whether this
- patch has already been read or not, or whether all patches have been
- read. You can also use <span style="font-weight: bold;">'n'</span>
- to move forward to the next unread patch. When you are finished, use
- the <span style="font-weight: bold;">'d'</span> to indicate that
- you are done. You can choose to finish before all the patches are
- read, and they will be saved to the .ti3 file. This is useful if you
- are unable to finish the chart in one session, and you can later <span
- style="text-decoration: underline;">resume</span> reading the
- chart by using the <span style="font-weight: bold;">chartread -r</span>
- flag.<br>
- <br>
- You can abort the whole process at any time by hitting Escape, and
- the readings will not be saved.<br>
- <br>
- <span style="font-weight: bold;"></span>
- <hr style="width: 100%; height: 2px;">
- <h3><a name="displaytype"></a>Display Type<br>
- </h3>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter<span class="titre"></span><br>
+ &nbsp;&nbsp;&nbsp; <a href="#SMCube">Palette/SwatchMate Cube</a>
+ &nbsp;&nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; - reflective
+ colorimeter<br>
+ <br>
+ Other instruments can be supported indirectly, since patch result
+ files created by other packages can be imported into Argyll.<br>
+ <span class="titre"><br>
+ General information about:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="#strip">Strip reading instruments</a><br>
+ </span>&nbsp;&nbsp;&nbsp; <a href="#xy">X-Y Table instruments</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="#spot">Spot reading instruments</a><br>
+ <span style="font-weight: bold;"></span><br>
+ <br>
+ There is a <a href="ccmxs.html">list of contributed</a> <span
+ style="font-weight: bold;">ccmx</span> (Colorimeter Correction
+ Matrix) files.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="strip"></a>Strip reading instruments</h3>
+ When used with a <span style="font-weight: bold;">DT20</span>, <span
+ style="font-weight: bold;">DTP41</span>, <span
+ style="font-weight: bold;">DTP51</span>, <span
+ style="font-weight: bold;">Eye-One Pro<span style="font-weight:
+ bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
+ strip reading instrument, chartread will first establish
+ communications with the instrument, and then set it up ready to read
+ the strips. The strips are labeled A to ZZ, and for each strip it
+ will prompt:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; About to read strip XX&nbsp; :<br>
+ <br>
+ where XX is the strip label, and this is followed by the available
+ options to navigate, read the strip, or finish. Note that the normal
+ (forward) direction of strip reading is one that starts at the strip
+ label.<br>
+ <br>
+ For the <span style="font-weight: bold;">DTP51</span> you should
+ feed the strip into the instrument, and the microswitch will trigger
+ the read.<br>
+ <br>
+ For the <span style="font-weight: bold;">DTP41</span> you should
+ line the appropriate strip up in the machine, and press its button.<br>
+ <br>
+ For the <span style="font-weight: bold;">Eye-One Pro</span> you
+ should set the guide to the appropriate strip, place the instrument
+ <span style="text-decoration: underline;">ahead</span> of the first
+ patch on blank paper, and then press and hold the instruments
+ button. When you hear a beep from the computer, you can then move
+ the instrument steadily over the patches, releasing the button after
+ the instrument is past the last patch. Moving the instrument too
+ fast or changing speeds may cause a mis-read, or a scan with few
+ samples read per patch.<br>
+ <br>
+ For the <span style="font-weight: bold;">ColorMunki</span> with the
+ default chart, the patches are the same width as the silver portion
+ of body (white version), or the textured portion of the body (black
+ version). Place aperture of the the instrument (located at its
+ center) in the white space ahead of the first patch, and then press
+ and hold the instruments button. When you hear a beep from the
+ computer, you can then move the instrument steadily over the
+ patches, releasing the button after the instrument is past the last
+ patch. Moving the instrument too fast or changing speeds may cause a
+ mis-read, or a scan with few samples read per patch. For the <span
+ style="font-weight: bold;">high density</span> ColorMunki chart (<a
+ href="printtarg.html#h">printtarg -h</a>), the patches are
+ arranged so that three rows are exactly the width of the&nbsp; body
+ of the instrument. If you are careful you can use this to guide the
+ center of the instrument over each row, or you may prefer to use
+ something like a plastic ruler to help guide the instrument.<br>
+ <br>
+ Using the <span style="font-weight: bold;">DTP20</span> or the <span
+ style="font-weight: bold;">Eye-One Pro</span> or <span
+ style="font-weight: bold;">ColorMunki</span> with a randomized
+ chart layout, the strip may be scanned from either direction. If a
+ randomized chart layout has not been used for the <span
+ style="font-weight: bold;">Eye-One Pro</span> or <span
+ style="font-weight: bold;">ColorMunki</span>, then the chart
+ should only be read in the one direction (use <a
+ href="chartread.html#B">chartread -B</a>).<br>
+ <br>
+ Note that you may have to check that system alert sounds are enabled
+ and at a suitable volume to in order to hear the beep prompt. For
+ the Eye-One Pro and ColorMunki, a second beep will sound after a
+ successfully read strip, or a double beep will sound,&nbsp;
+ indicating a failure or warning that needs attention. See also the
+ note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
+ <br>
+ If the strip is read successfully there will be a single "success"
+ beep, and the line will be followed with:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; : <br>
+ &nbsp;&nbsp;&nbsp; Strip read OK<br>
+ <br>
+ If there is an error of some sort there will be a double "fail"
+ beep, and a message will be issued, and you will be asked whether to
+ abort the chart reading, or retry the<br>
+ failed strip:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip XX&nbsp; : <br>
+ &nbsp;&nbsp;&nbsp; Strip read failed due to misread (Not enough
+ patches)<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
+ <br>
+ If you are unable to successfully read a strip after several
+ retries, you can skip that strip using the <span
+ style="font-weight: bold;">'n'</span> key, and save<br>
+ the chart readings without that strip.<br>
+ <br>
+ If the strip is read successfully, but the patches values don't seem
+ to be what is expected, you will get a double "fail" beep&nbsp; and
+ the following type of warning:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; (Warning) Seem to have read strip&nbsp; YY&nbsp;
+ rather than&nbsp; XX !<br>
+ &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
+ retry, Esc, ^C or Q to give up:<br>
+ <br>
+ This could be because you have accidentally read the wrong strip (a
+ common mistake), or it could be that the device response is so
+ different from what is expected that warning is erroneous, or you
+ may get a lot of these sorts of warnings if you are accidentally
+ reading the wrong chart. You may also get this sort of warning if
+ you are not using bi-direction reading (chartread -B), and read the
+ strip from the wrong end.<br>
+ If you are absolutely sure you lined up the correct strip, then hit
+ return, otherwise line the appropriate strip up again, and hit some
+ other key (ie. space).<br>
+ Erroneous warnings are less likely if a previous profile for a
+ device was given to <span style="font-weight: bold;">targen</span>
+ to set more accurate expectations.<br>
+ <br>
+ You may also see the following type of warning:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; (Warning) Patch error YY.YYY (&gt;35 not good,
+ &gt;95 bad)<br>
+ &nbsp;&nbsp; There is at least one patch with an very unexpected
+ response!<br>
+ &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
+ retry, Esc, ^C or Q to give up:<br>
+ <br>
+ Similar to the previous warning, this indicates that while the right
+ strip appears to have been read, one of the patch readings is quite
+ different to what is expected. This may indicate an error of some
+ sort (ie. damaged test chart, or bad instrument positioning), or may
+ be erroneous if the actual device response is quite different to the
+ expectation. Erroneous warnings are less likely if a previous
+ profile for a device was given to <span style="font-weight: bold;">targen</span>
+ to set more accurate expectations.<br>
+ <br>
+ You can also navigate the next strip to be read using the <span
+ style="font-weight: bold;">'f'</span> key to move forward and the
+ <span style="font-weight: bold;">'b'</span> keys<span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
+ to move backwards. The prompt will indicate whether this strip has
+ already been read or not, or whether all strips have been read. You
+ can also use <span style="font-weight: bold;">'n'</span> to move
+ forward to the next unread strip. After each successful reading it
+ will move forward to the next unread strip. When you are finished,
+ use the <span style="font-weight: bold;">'d'</span> to indicate
+ that you are done. You can choose to finish before all the strips
+ are read, and the patches that have been read will be saved to the
+ .ti3 file. This is useful if you are unable to read a particular
+ strip successfully, or if you are unable to finish the chart in one
+ session, and you can later <span style="text-decoration:
+ underline;">resume</span> reading the chart by using the <span
+ style="font-weight: bold;">chartread -r</span> flag. [You could
+ resume reading the chart patch by patch using the <span
+ style="font-weight: bold;">chartread -r -p</span> if you are
+ unable to read a strip successfully.]<br>
+ <br>
+ When reading in patch by patch mode, there are a few additional
+ navigation options, such as <span style="font-weight: bold;"><span
+ style="font-weight: bold;">F</span></span> to move forward 10
+ patches, <span style="font-weight: bold;">B</span> to move
+ backwards 10 patches, and <span style="font-weight: bold;">g</span>
+ to go to a specific patch.<br>
+ <br>
+ You can abort the whole process at any time by hitting Escape, and
+ the readings will not be saved.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="xy"></a>X-Y Table instruments</h3>
+ When you are using an XY table type instrument, such as a Gretag <span
+ style="font-weight: bold;">SpectroScan</span>, &nbsp;chartread
+ will first establish communications with the instrument, and then
+ set it up ready to read the chart. You will be prompted for each
+ sheet with a message such as:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Please make sure that the white reference is in
+ slot 1, then<br>
+ &nbsp;&nbsp;&nbsp; place sheet 1 of 4 on table, then<br>
+ &nbsp;&nbsp;&nbsp; hit return to continue, Esc to give up<br>
+ <br>
+ After hitting return you will be prompted to line up three squares
+ on the sheet, one at a time:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Using the XY table controls, locate patch A1 with
+ the sight,<br>
+ &nbsp;&nbsp;&nbsp; then hit return to continue, Esc to give up<br>
+ <br>
+ On completing this, the instrument will commence reading each sheet.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="spot"></a>Spot reading instruments</h3>
+ When used with a <span style="font-weight: bold;">DT22</span> or <span
+ style="font-weight: bold;">SpectroLino</span> or use the patch by
+ patch reading mode (<span style="font-weight: bold;">chartread -p</span>)
+ with the <span style="font-weight: bold;"></span> <span
+ style="font-weight: bold;">Eye-One Pro<span style="font-weight:
+ bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
+ instrument, or use the external values mode (<span
+ style="font-weight: bold;">chartread -x</span>), chartread will
+ first establish communications with the instrument, and then set it
+ up ready to read the patches. The patches are typically labeled by
+ column A to ZZ, and row 1-999. Each patch will prompt:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch 'XX'&nbsp; :<br>
+ <br>
+ where XX is the patch label, and this is followed by the available
+ options to navigate, read the strip, or finish.<br>
+ <br>
+ Place the instrument on the indicated patch, and trigger a reading
+ using one of the available methods (typically using the instrument
+ switch of pressing a key).<br>
+ <br>
+ There should be an audible prompt on a successful or failed reading.
+ <br>
+ <br>
+ Note that you may have to check that system alert sounds are enabled
+ and at a suitable volume to in order to hear the beep prompt. For
+ the Eye-One Pro and ColorMunki, a second beep will sound after a
+ successfully read strip, or a double beep will sound,&nbsp;
+ indicating a failure or warning that needs attention. See also the
+ note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
+ <br>
+ If the patch is read successfully, the line will be completed with:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; Patch read OK<br>
+ <br>
+ If there is an error of some sort, a message will be issued, and you
+ will be asked whether to abort the chart reading, or retry the<br>
+ failed patch:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch XX&nbsp; : read_strip
+ returned 'Strip misread' (Bad reading)<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Strip read failed due to misread<br>
+ &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
+ <br>
+ You can navigate the next patch to be read using the <span
+ style="font-weight: bold;">'f'</span> key to move forward and the
+ <span style="font-weight: bold;">'b'</span> keys<span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
+ to move backwards, while <span style="font-weight: bold;">'F'</span>
+ and <span style="font-weight: bold;">'B'</span> will move forward
+ and backwards by 10 patches. The prompt will indicate whether this
+ patch has already been read or not, or whether all patches have been
+ read. You can also use <span style="font-weight: bold;">'n'</span>
+ to move forward to the next unread patch. When you are finished, use
+ the <span style="font-weight: bold;">'d'</span> to indicate that
+ you are done. You can choose to finish before all the patches are
+ read, and they will be saved to the .ti3 file. This is useful if you
+ are unable to finish the chart in one session, and you can later <span
+ style="text-decoration: underline;">resume</span> reading the
+ chart by using the <span style="font-weight: bold;">chartread -r</span>
+ flag.<br>
+ <br>
+ You can abort the whole process at any time by hitting Escape, and
+ the readings will not be saved.<br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="displaytype"></a>Display Type<br>
+ </h3>
Many of the colorimeters have a <span style="font-weight: bold;">display
@@ -1265,152 +1459,200 @@
- type</span> selection parameter. Depending on the instrument, this
- may combine two related functions: 1) Changing the measurement mode
- to suite either refresh-type, or non-refresh displays, and 2)
- Changing the calibration to suite a particular displays spectral
- characteristics.<br>
- <br>
- A refresh type display uses a technology that presents different
- portions of the image at different times, doing so at a high enough
- rate that this is normally imperceptible. This time varying
- characteristic can interfere with measuring a display color unless
- the instrument makes allowances for it, typically by making its
- measurement period a multiple of the display refresh period. Display
- types that <span style="font-weight: bold;">refresh</span> are CRT
- (Cathode Ray Tube), Single chip DLP (Digital Light Processing) and
- Plasma displays. An example of a <span style="font-weight: bold;">non-refresh</span>
- display technology is LCD (Liquid Crystal Display), although is a
- few cases the back-light illumination may have a low enough
- frequency flicker to benefit from the refresh mode.<br>
- <br>
- Instruments in which the display type selection only changes the
- measurement mode (i.e. i1d3), will typically have some other
- independent option to set the calibration type. Simpler instruments
- combine the measurement mode with a calibration selections,
- typically refresh+CRT and non-refresh+LCD. Some instruments are a
- hybrid of both (Spyder4), where the display type can select between
- generic refresh/non-refresh that can then use a .CCSS to set the
- calibration type, or a combined selection of non-refresh and a
- particular display type.<br>
- <br>
- See <a
- href="http://en.wikipedia.org/wiki/Comparison_of_display_technology">Comparison_of_display_technology</a>
- for some background on different display technologies.<br>
- <br>
- <hr size="2" width="100%"><br>
- <h3><a name="refreshmeasurement"></a>Refresh Rate Measurement</h3>
- <p>Most of the colorimeters that have a refresh display type
- selection, also have an ability to measure the refresh rate of a
- display. Some of the spectrometers also have a display refresh
- rate measurement capability when in an emissive measurement mode,
- even though they don't use this to support a refresh display mode.
- You can do a display refresh rate measurement in <a
- href="spotread.html">spotread</a> using the <b>'F' </b>key.
- The particular instruments have a range of accuracy when making
- this measurement. A rough guide is as follows:<br>
- <br>
- </p>
- <table border="1" cellpadding="2" cellspacing="2" width="372"
- height="230">
- <tbody>
- <tr>
- <td valign="top"><b>Instrument</b></td>
- <td valign="top"><b>Typical error in Hz.</b></td>
- </tr>
- <tr>
- <td valign="top">spectrobos 1211/1201<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- <tr>
- <td valign="top">Klein K10-A<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- <tr>
- <td valign="top">DTP92<br>
- </td>
- <td valign="top">0.1<br>
- </td>
- </tr>
- <tr>
- <td valign="top">i1 Display 2<br>
- </td>
- <td valign="top">0.5<br>
- </td>
- </tr>
- <tr>
- <td valign="top">Spyder 2<br>
- </td>
- <td valign="top">0.7<br>
- </td>
- </tr>
- <tr>
- <td valign="top">Spyder 3<br>
- </td>
- <td valign="top">3<br>
- </td>
- </tr>
- <tr>
- <td valign="top">Spyder 4<br>
- </td>
- <td valign="top">3<br>
- </td>
- </tr>
- <tr>
- <td valign="top">i1 Display Pro<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- <tr>
- <td valign="top">i1 Pro Spectro.<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- <tr>
- <td valign="top">ColorMunki Spectro.<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- </tbody>
- </table>
- <p><br>
- </p>
- <hr size="2" width="100%">
- <p><span style="font-weight: bold;"><a name="specbos"></a><span
- style="font-weight: bold;">specbos 1211 and 1201
- Tele-Spectro-Radiometer<br>
- </span></span></p>
- <img alt="JETI specbos 1211" src="JETI_1211.jpg" width="257"
- height="254">
- <p><span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">specbos 1211</span><span
- style="font-weight: bold;"> </span>and <b>1201</b> from <a
- href="http://www.jeti.com/">JETI</a>&nbsp; are currently
- available instruments. These are reference grade instruments
- capable of emissive and ambient measurements, and are often used
- for monitor, projector and cinema calibration &amp;
- characterization, lighting measurement and colorimeter
- calibration, amongst many other uses.<br>
- </p>
- <hr size="2" width="100%">
- <p><span style="font-weight: bold;"><a name="ex1"></a><span
- style="font-weight: bold;">Image Engineering EX1<br>
- </span></span></p>
- <img alt="Image Engineering EX1" src="EX1.jpg" width="253"
- height="158"> <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;"><br>
- Availability:<br>
- <br>
- </span>The <a
+
+
+
+
+
+
+
+
+
+
+
+ type</span> selection parameter. Depending on the instrument, this
+ may combine two related functions: 1) Changing the measurement mode
+ to suite either refresh-type, or non-refresh displays, and 2)
+ Changing the calibration to suite a particular displays spectral
+ characteristics.<br>
+ <br>
+ A refresh type display uses a technology that presents different
+ portions of the image at different times, doing so at a high enough
+ rate that this is normally imperceptible. This time varying
+ characteristic can interfere with measuring a display color unless
+ the instrument makes allowances for it, typically by making its
+ measurement period a multiple of the display refresh period. Display
+ types that <span style="font-weight: bold;">refresh</span> are CRT
+ (Cathode Ray Tube), Single chip DLP (Digital Light Processing) and
+ Plasma displays. An example of a <span style="font-weight: bold;">non-refresh</span>
+ display technology is LCD (Liquid Crystal Display), although is a
+ few cases the back-light illumination may have a low enough
+ frequency flicker to benefit from the refresh mode.<br>
+ <br>
+ Instruments in which the display type selection only changes the
+ measurement mode (i.e. i1d3), will typically have some other
+ independent option to set the calibration type. Simpler instruments
+ combine the measurement mode with a calibration selections,
+ typically refresh+CRT and non-refresh+LCD. Some instruments are a
+ hybrid of both (Spyder4), where the display type can select between
+ generic refresh/non-refresh that can then use a .CCSS to set the
+ calibration type, or a combined selection of non-refresh and a
+ particular display type.<br>
+ <br>
+ See <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology">Comparison_of_display_technology</a>
+ for some background on different display technologies.<br>
+ <br>
+ <hr size="2" width="100%"><br>
+ <h3><a name="refreshmeasurement"></a>Refresh Rate Measurement</h3>
+ <p>Most of the colorimeters that have a refresh display type
+ selection, also have an ability to measure the refresh rate of a
+ display. Some of the spectrometers also have a display refresh
+ rate measurement capability when in an emissive measurement mode,
+ even though they don't use this to support a refresh display mode.
+ You can do a display refresh rate measurement in <a
+ href="spotread.html">spotread</a> using the <b>'F' </b>key.
+ The particular instruments have a range of accuracy when making
+ this measurement. A rough guide is as follows:<br>
+ <br>
+ </p>
+ <table border="1" cellpadding="2" cellspacing="2" width="372"
+ height="230">
+ <tbody>
+ <tr>
+ <td valign="top"><b>Instrument</b></td>
+ <td valign="top"><b>Typical error in Hz.</b></td>
+ </tr>
+ <tr>
+ <td valign="top">spectrobos 1211/1201/1501/1511<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Klein K10-A<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">DTP92<br>
+ </td>
+ <td valign="top">0.1<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Display 2<br>
+ </td>
+ <td valign="top">0.5<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 2<br>
+ </td>
+ <td valign="top">0.7<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 3<br>
+ </td>
+ <td valign="top">3<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 4<br>
+ </td>
+ <td valign="top">3<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Display Pro<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Pro Spectro.<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">ColorMunki Spectro.<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <p><br>
+ </p>
+ <hr size="2" width="100%">
+ <p><span style="font-weight: bold;"><a name="specbos"></a><span
+ style="font-weight: bold;">specbos 1211 and 1201
+ Tele-Spectro-Radiometer<br>
+ </span></span></p>
+ <img alt="JETI specbos 1211" src="JETI_1211.jpg" width="257"
+ height="254">
+ <p><span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">specbos 1211</span><span
+ style="font-weight: bold;"> </span>and <b>1201</b> from <a
+ href="http://www.jeti.com/">JETI</a>&nbsp; are currently
+ available instruments. These are reference grade instruments
+ capable of emissive and ambient measurements, and are often used
+ for monitor, projector and cinema calibration &amp;
+ characterization, lighting measurement and colorimeter
+ calibration, amongst many other uses.<br>
+ </p>
+ <p>The <b>JETI</b> specbos <span style="font-weight: bold;">1211</span><span
+ style="font-weight: bold;"> </span>and <b>1201</b> makes use
+ of the FTDI FT232R Virtual COM Port Drivers (VCP), that may need
+ installing for your operating system. See <a
+ href="file:///D:/src/argyll/doc/Installing.html">installation
+ instructions</a>. </p>
+ <br>
+ <hr size="2" width="100%">
+ <p><span style="font-weight: bold;"><a name="specbos"></a><span
+ style="font-weight: bold;">spectraval 1511 and 1501
+ Tele-Spectro-Radiometer<br>
+ </span></span></p>
+ <img alt="JETI spectraval 1501" src="JETI_1501.jpg" width="167"
+ height="253"> <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">spectraval 1511</span><span
+ style="font-weight: bold;"> </span>and <b>1501</b> from <a
+ href="http://www.jeti.com/">JETI</a>&nbsp; are currently available
+ instruments. These are high grade instruments capable of emissive
+ measurements, and are often used for monitor, projector and cinema
+ calibration &amp; characterization and colorimeter calibration,
+ amongst many other uses.<br>
+ <br>
+ The <b>JETI</b> specbos <span style="font-weight: bold;">1511</span><span
+ style="font-weight: bold;"> </span>and <b>1501</b> makes use of
+ the newer FTDI FT231XS Virtual COM Port Drivers (VCP), that may need
+ installing for your operating system. See <a href="Installing.html">installation
+
+ instructions</a>.<br>
+ <br>
+ <b>Bluetooth:</b> These instruments can be operated via Bluetooth by
+ first pairing the instrument with your computer and enabling the
+ Bluetooth serial port, and then allowing the ArgyllCMS tools to
+ identify the instrument over the serial port. <br>
+ <br>
+ <hr size="2" width="100%">
+ <p><span style="font-weight: bold;"><br>
+ <a name="ex1"></a><span style="font-weight: bold;">Image
+ Engineering EX1<br>
+ </span></span></p>
+ <img alt="Image Engineering EX1" src="EX1.jpg" width="253"
+ height="158"> <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;"><br>
+ Availability:<br>
+ <br>
+ </span>The <a
href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/ex1">Image
@@ -1418,20 +1660,31 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
- Engineering EX1</a> is a currently available instruments. This is
- a high resolution spectrometer intended for the measurement of light
- sources.
- <p> </p>
- <p><br>
- </p>
- <hr size="2" width="100%">
- <p><span style="font-weight: bold;"><a name="k10a"></a><span
- style="font-weight: bold;">Klein K10-A Colorimeter<br>
- </span></span></p>
- <img alt="Klein K10-A" src="K10A.jpg" width="267" height="236"><br>
- <p><span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ Engineering EX1</a> is a currently available instruments. This is
+ a high resolution spectrometer intended for the measurement of light
+ sources.
+ <p> </p>
+ <p><br>
+ </p>
+ <hr size="2" width="100%">
+ <p><span style="font-weight: bold;"><a name="k10a"></a><span
+ style="font-weight: bold;">Klein K10-A Colorimeter<br>
+ </span></span></p>
+ <img alt="Klein K10-A" src="K10A.jpg" width="267" height="236"><br>
+ <p><span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
</span>The <span style="font-weight: bold;">Klein K10-A </span>from
@@ -1446,6 +1699,17 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
+
+
+
+
+
+
+
+
+
+
+
<a href="http://www.kleininstruments.com/">Klein Instruments</a>&nbsp;
@@ -1460,276 +1724,317 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
- is a currently available instrument. It is noted for it's speed,
- high precision, and ability to measure to very low light
- levels.This is a high end instruments capable of contact and tele
- - emissive, and ambient measurements, and are often used for
- monitor, projector and cinema calibration and characterization. <br>
- </p>
- <p>Note that unlike the operation of other instruments, the Ambient
- mode is purely manual - the diffuser must be fitted and then the
- appropriate calibration setting chosen (Typically with "Lux" in
- the name).<br>
- </p>
- <p>By default, more measurements are taken and averaged together
- when the light level is low. This can be disabled and a single
- measurement taken per reading, to gain maximum speed by using the
- -Y A flag.<br>
- </p>
- <p>The <b>K-1</b>, <b>K-8</b> and&nbsp; <b>K-10</b> are also
- reported to work. </p>
- <p> </p>
- <hr size="2" width="100%">
- <p><br>
- </p>
- <span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"><a name="ColorMunki"></a><span
- style="font-weight: bold;">ColorMunki </span>Design or Photo <span
- style="font-weight: bold;">reflective/emissive spectrometer</span><br>
- <br>
- <img style="width: 272px; height: 243px;" alt="" title="ColorMunki
- (White)" src="ColorMunki.jpg">&nbsp;&nbsp; <br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">ColorMunki</span> <span
- style="font-weight: bold;">Design or Photo </span>from <a
- href="http://www.xrite.com/">X-Rite</a>&nbsp; is currently
- available in two different packages from the manufacturer. These
- packages differ in what features the manufacturers software
- provides, as well as cosmetic differences between the instrument
- (white and black). This comparison <a
- href="http://www.colormunki.com/product/show?page=2">chart</a>
- illustrates the differences. Used with Argyll, there are no
- differences in operation of a ColorMunki instrument, irrespective of
- which package it came with. The ColorMunki Design has the lowest
- RRP, but the Photo package may be cheaper with discounting .<br>
- <br>
- <span style="font-weight: bold;">Limitations &amp; Features:</span><br>
- <br>
- Unlike the Eye-One Pro, the ColorMunki is only available in a U.V.
- Cut (ie. "Ultra Violet filtered") model. This means that it is not
- suitable for use with the&nbsp; Fluorescent Whitener Additive
- Compensation option in Argyll (see <a href="FWA.html">here</a> for
- a discussion about what FWA compensation is).<br>
- <br>
- Like the Eye-One Pro, this instrument does support the <a
- href="spotread.html#H">high resolution</a> spectral mode.<br>
- <br>
- <span style="font-weight: bold;">OS X and X-Rite drivers</span><br>
- <br>
- Please note the installation <a
- href="Installing_OSX.html#ColorMunki">instructions</a>.<br>
- <br>
- <span style="font-weight: bold;">Tips &amp; Tricks:<br>
- <br>
- </span>In handling the instrument when about to make a reading, be
- very careful not to accidentally press the switch - it is large and
- easily pressed by accident. A guide of some sort (ie. a plastic
- ruler) can help a lot in&nbsp; keeping the instrument over a line
- of&nbsp; patches. <br>
- <br>
- <span style="font-weight: bold;">Patch recognition:</span><br>
- <br>
- For the best chances of good patch recognition, the instrument
- should be drawn smoothly and not too rapidly over the strip. (This
- can be a little tricky due to the two small rubber feet on the
- bottom of the device that aid its spot reading guide.) If there is a
- misread, try slowing down slightly. Generally a higher quality set
- of readings will result if slower scans are used, since there will
- then be more samples averaged for each patch. <br>
- <br>
- In <a href="chartread.html">chartread</a>, the -<span
- style="font-weight: bold;">T ratio</span> argument modifies the
- patch consistency tolerance threshold for the ColorMunki. In
- recognizing patches in a strip, the instrument takes multiple
- readings as the strip is read, and then divide the readings up into
- each patch. It then check the consistency of the multiple readings
- corresponding to each patch, and reject the measurement if they are
- too inconsistent. For some media (ie. a coarser screens, fabric
- etc.) the default tolerance may be unreasonably tight, so the <span
- style="font-weight: bold;">-T ratio</span> argument can be used to
- modify this criteria. To loosen the tolerance, use a number greater
- than 1.0 (ie. 1.5, 2.0). <br>
- <br>
- Note that <a href="printtarg.html">printtarg</a> provides the <a
- href="printtarg.html#h">-h</a> option that allows the choice of
- two different patch row widths with ColorMunki test charts. [Some
- people have successfully used the i1Pro patch layout with the
- ColorMunki, by making a guide to keep it over the much narrower
- patchs.]<br>
- <br>
- <span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
- style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="DTP20"></a></span><span style="font-weight: bold;">DTP20
- "Pulse" reflective spectrometer<br>
- <br>
- </span><span style="font-weight: bold;"><img title="DTP20" alt=""
- src="DTP20.jpg" style="width: 304px; height: 210px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP20</span> from <a
- href="http://www.xrite.com/">X-Rite</a> was discontinued during
- 2007, but may still be available from old stock or second hand. <br>
- <br>
- <span style="font-weight: bold;">Special features:</span><br>
- <br>
- The <span style="font-weight: bold;">DTP20</span> has a couple of
- unique features that Argyll can take advantage of. One is that it
- can operate un-tethered (off line). A whole chart can be read
- un-tethered by first clearing any previous readings in the
- instrument, then reading the chart TID strip, before reading all the
- other strips. The instrument can then be connected up to <span
- style="font-weight: bold;">chartread</span>, which will recognize
- the chart, and download all the measurements.<br>
- If there is no chart in the instrument when chartread connects to
- it, then it will use the strip by strip tethered mode, just like the
- other strip instruments. If the right number of spot readings are
- present in the instrument, these will be used by <span
- style="font-weight: bold;">chartread</span> too.<br>
- <br>
- Un-tethered spot measurements can also be read in using&nbsp; <span
- style="font-weight: bold;">spotread</span>, which will notice the
- stored readings, and offer to print them out, or they can be
- ignored, and tethered readings taken. This will clear any saved spot
- readings.<br>
- <br>
- <span style="font-weight: bold;">Note</span> that tethered (on-line)
- strip reading will only work if the firmware in the device is
- version 1.03 or greater. You can check the firmware version by
- running with the verbose option: <span style="font-weight: bold;">-v<br>
- <br>
- Chart printing:<br>
- <span style="font-weight: bold;"><br>
- </span></span>Because the DTP20 measures exact distances using the
- markings on its ruler, it's critical that the chart be printed out
- exactly the right size. If the chart gets re-sized at all in the
- process of printing it, the DTP20 is likely to fail in reading it.
- If you have a problem with this, you might want to increase the page
- margins using the <span style="font-weight: bold;">printtarg -m</span>
- parameter, or find a printing path that preserves the test chart
- size correctly.<br>
- <br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
- style="font-weight: bold;">Operation:<br>
- <br>
- </span>When reading in tethered (on-line) mode, that the instrument
- takes <span style="font-weight: bold;">several seconds</span> to
- download the measurements after each strip, and that the indicator
- will be in "rainbow" mode while this occurs. <span
- style="text-decoration: underline;">Wait</span> until the
- indicator turns solid green again before starting to measure the
- next strip.<br>
- <br>
- To <span style="font-weight: bold;">reset</span> the instrument and
- clear any stored readings: press the button three times in quick
- succession. The indicator will turn solid blue. Then hold the button
- down until the instrument beeps and the indicator goes out. Release
- the button and the indicator should flash then return to solid green
- (ready).<br>
- <br>
- To <span style="font-weight: bold;">calibrate</span> the
- instrument, place it on its calibration tile, then press the button
- three times in quick succession.The indicator will turn solid blue.
- Click the button another three times in quick succession, and the
- indicator should turn yellow. Then hold the button down until the
- instrument beeps and the indicator goes out. Release the button and
- the instrument should flash and then turn solid green.<br>
- <br>
- If the chart is particularly <span style="font-weight: bold;">small</span>,
- the patches may end up printed very close to the edge of the chart,
- and therefore it may be difficult to confine your scan to the chart,
- and passing<br>
- the instrument over the edge of the chart may prevent it reading
- successfully. One way of working around this is to place the chart
- on a larger piece of paper of the same type.<br>
- <br>
- The <span style="font-weight: bold;">speed</span> of scan can be
- quite critical with this instrument. In particular, it doesn't work
- very well if the scan is too <span style="font-weight: bold;">slow</span>.
- You don't want to go too fast either, as this reduces the number of
- samples per patch.<br>
- <br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
- style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="DTP22"></a></span><span style="font-weight: bold;">DTP22
- Digital Swatchbook reflective spectrometer</span><br>
- <span style="font-weight: bold;"><br>
- <img alt="" src="DTP22.jpg" style="width: 222px; height: 193px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP22</span> from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument.&nbsp; It may still be available second hand. It is
- capable of reading colored patches one at a time.<br>
- <br>
- <br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="DTP41"></a>DTP41 reflective, DTP41T
- reflective/transmissive spectrometers<br>
- <br>
- <img alt="" src="DTP41.jpg" style="width: 263px; height: 298px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP41</span> and <span
- style="font-weight: bold;">DTP41T</span> from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument.&nbsp; It may still be available second hand. <br>
- <br>
- The series II instruments (<span style="font-weight: bold;">DTP41B</span>
- and <span style="font-weight: bold;">DTP41TB</span>) offer both
- serial and USB connection. Note that currently only serial operation
- using Argyll is possible with these instruments.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <a name="dtp51"></a><span style="font-weight: bold;">DTP51
- reflective colorimeter<br>
- <br>
- <img alt="" src="DTP51.jpg" style="width: 263px; height: 223px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP51</span> from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument.&nbsp; It may still be available second hand. <br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"><br>
- </span></span>The DTP51's switch is triggered by inserting a strip
- into the slot.<br>
- <br>
- <br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="DTP92"></a>DTP92 CRT display colorimeter<br>
- <br>
- <img alt="" src="DTP92.jpg" style="width: 223px; height: 180px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP92</span><span
- style="font-weight: bold;"></span> from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument.&nbsp; It may still be available second hand. It will
- only read CRT technology displays.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ is a currently available instrument. It is noted for it's speed,
+ high precision, and ability to measure to very low light
+ levels.This is a high end instruments capable of contact and tele
+ - emissive, and ambient measurements, and are often used for
+ monitor, projector and cinema calibration and characterization. <br>
+ </p>
+ <p>Note that unlike the operation of other instruments, the Ambient
+ mode is purely manual - the diffuser must be fitted and then the
+ appropriate calibration setting chosen (Typically with "Lux" in
+ the name).<br>
+ </p>
+ <p>By default, more measurements are taken and averaged together
+ when the light level is low. This can be disabled and a single
+ measurement taken per reading, to gain maximum speed by using the
+ -Y A flag.<br>
+ </p>
+ <p>The <b>K-1</b>, <b>K-8</b> and&nbsp; <b>K-10</b> are also
+ reported to work.<br>
+ </p>
+ <p>The&nbsp; <b>Klien K10A</b> makes use of the FTDI FT232R Virtual
+ COM Port Drivers (VCP), that may need installing for your
+ operating system. See <a href="Installing.html">installation
+ instructions</a>.</p>
+ <p> </p>
+ <hr size="2" width="100%">
+ <p><br>
+ </p>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><a name="ColorMunki"></a><span
+ style="font-weight: bold;">ColorMunki </span>Design or Photo <span
+ style="font-weight: bold;">reflective/emissive spectrometer</span><br>
+ <br>
+ <img style="width: 272px; height: 243px;" alt="" title="ColorMunki
+ (White)" src="ColorMunki.jpg">&nbsp;&nbsp; <br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">ColorMunki</span> <span
+ style="font-weight: bold;">Design or Photo </span>from <a
+ href="http://www.xrite.com/">X-Rite</a>&nbsp; is currently
+ available in two different packages from the manufacturer. These
+ packages differ in what features the manufacturers software
+ provides, as well as cosmetic differences between the instrument
+ (white and black). This comparison <a
+ href="http://www.colormunki.com/product/show?page=2">chart</a>
+ illustrates the differences (Note that the ColorMunki Design comes
+ with <b>Pantone</b> libraries). Used with Argyll, there are no
+ differences in operation of a ColorMunki instrument, irrespective of
+ which package it came with. The ColorMunki Design has the lowest
+ RRP, but the Photo package may be cheaper with discounting .<br>
+ <br>
+ <span style="font-weight: bold;">Limitations &amp; Features:</span><br>
+ <br>
+ Unlike the Eye-One Pro, the ColorMunki is only available in a U.V.
+ Cut (ie. "Ultra Violet filtered") model. This means that it is not
+ suitable for use with the&nbsp; Fluorescent Whitener Additive
+ Compensation option in Argyll (see <a href="FWA.html">here</a> for
+ a discussion about what FWA compensation is).<br>
+ <br>
+ Like the Eye-One Pro, this instrument does support the <a
+ href="spotread.html#H">high resolution</a> spectral mode.<br>
+ <br>
+ <span style="font-weight: bold;">OS X and X-Rite drivers</span><br>
+ <br>
+ Please note the installation <a
+ href="Installing_OSX.html#ColorMunki">instructions</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Tips &amp; Tricks:<br>
+ <br>
+ </span>In handling the instrument when about to make a reading, be
+ very careful not to accidentally press the switch - it is large and
+ easily pressed by accident. A guide of some sort (ie. a plastic
+ ruler) can help a lot in&nbsp; keeping the instrument over a line
+ of&nbsp; patches. <br>
+ <br>
+ <span style="font-weight: bold;">Patch recognition:</span><br>
+ <br>
+ For the best chances of good patch recognition, the instrument
+ should be drawn smoothly and not too rapidly over the strip. (This
+ can be a little tricky due to the two small rubber feet on the
+ bottom of the device that aid its spot reading guide.) If there is a
+ misread, try slowing down slightly. Generally a higher quality set
+ of readings will result if slower scans are used, since there will
+ then be more samples averaged for each patch. <br>
+ <br>
+ In <a href="chartread.html">chartread</a>, the -<span
+ style="font-weight: bold;">T ratio</span> argument modifies the
+ patch consistency tolerance threshold for the ColorMunki. In
+ recognizing patches in a strip, the instrument takes multiple
+ readings as the strip is read, and then divide the readings up into
+ each patch. It then check the consistency of the multiple readings
+ corresponding to each patch, and reject the measurement if they are
+ too inconsistent. For some media (ie. a coarser screens, fabric
+ etc.) the default tolerance may be unreasonably tight, so the <span
+ style="font-weight: bold;">-T ratio</span> argument can be used to
+ modify this criteria. To loosen the tolerance, use a number greater
+ than 1.0 (ie. 1.5, 2.0). <br>
+ <br>
+ Note that <a href="printtarg.html">printtarg</a> provides the <a
+ href="printtarg.html#h">-h</a> option that allows the choice of
+ two different patch row widths with ColorMunki test charts. [Some
+ people have successfully used the i1Pro patch layout with the
+ ColorMunki, by making a guide to keep it over the much narrower
+ patchs.]<br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively X-Rite <a
+ href="http://www.xrite.com/xrite-graphic-arts-standard">XRGA</a>.<br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP20"></a></span><span style="font-weight: bold;">DTP20
+ "Pulse" reflective spectrometer<br>
+ <br>
+ </span><span style="font-weight: bold;"><img title="DTP20" alt=""
+ src="DTP20.jpg" style="width: 304px; height: 210px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP20</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> was discontinued during
+ 2007, but may still be available from old stock or second hand. <br>
+ <br>
+ <span style="font-weight: bold;">Special features:</span><br>
+ <br>
+ The <span style="font-weight: bold;">DTP20</span> has a couple of
+ unique features that Argyll can take advantage of. One is that it
+ can operate un-tethered (off line). A whole chart can be read
+ un-tethered by first clearing any previous readings in the
+ instrument, then reading the chart TID strip, before reading all the
+ other strips. The instrument can then be connected up to <span
+ style="font-weight: bold;">chartread</span>, which will recognize
+ the chart, and download all the measurements.<br>
+ If there is no chart in the instrument when chartread connects to
+ it, then it will use the strip by strip tethered mode, just like the
+ other strip instruments. If the right number of spot readings are
+ present in the instrument, these will be used by <span
+ style="font-weight: bold;">chartread</span> too.<br>
+ <br>
+ Un-tethered spot measurements can also be read in using&nbsp; <span
+ style="font-weight: bold;">spotread</span>, which will notice the
+ stored readings, and offer to print them out, or they can be
+ ignored, and tethered readings taken. This will clear any saved spot
+ readings.<br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that tethered (on-line)
+ strip reading will only work if the firmware in the device is
+ version 1.03 or greater. You can check the firmware version by
+ running with the verbose option: <span style="font-weight: bold;">-v<br>
+ <br>
+ Chart printing:<br>
+ <span style="font-weight: bold;"><br>
+ </span></span>Because the DTP20 measures exact distances using the
+ markings on its ruler, it's critical that the chart be printed out
+ exactly the right size. If the chart gets re-sized at all in the
+ process of printing it, the DTP20 is likely to fail in reading it.
+ If you have a problem with this, you might want to increase the page
+ margins using the <span style="font-weight: bold;">printtarg -m</span>
+ parameter, or find a printing path that preserves the test chart
+ size correctly.<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;">Operation:<br>
+ <br>
+ </span>When reading in tethered (on-line) mode, that the instrument
+ takes <span style="font-weight: bold;">several seconds</span> to
+ download the measurements after each strip, and that the indicator
+ will be in "rainbow" mode while this occurs. <span
+ style="text-decoration: underline;">Wait</span> until the
+ indicator turns solid green again before starting to measure the
+ next strip.<br>
+ <br>
+ To <span style="font-weight: bold;">reset</span> the instrument and
+ clear any stored readings: press the button three times in quick
+ succession. The indicator will turn solid blue. Then hold the button
+ down until the instrument beeps and the indicator goes out. Release
+ the button and the indicator should flash then return to solid green
+ (ready).<br>
+ <br>
+ To <span style="font-weight: bold;">calibrate</span> the
+ instrument, place it on its calibration tile, then press the button
+ three times in quick succession.The indicator will turn solid blue.
+ Click the button another three times in quick succession, and the
+ indicator should turn yellow. Then hold the button down until the
+ instrument beeps and the indicator goes out. Release the button and
+ the instrument should flash and then turn solid green.<br>
+ <br>
+ If the chart is particularly <span style="font-weight: bold;">small</span>,
+ the patches may end up printed very close to the edge of the chart,
+ and therefore it may be difficult to confine your scan to the chart,
+ and passing<br>
+ the instrument over the edge of the chart may prevent it reading
+ successfully. One way of working around this is to place the chart
+ on a larger piece of paper of the same type.<br>
+ <br>
+ The <span style="font-weight: bold;">speed</span> of scan can be
+ quite critical with this instrument. In particular, it doesn't work
+ very well if the scan is too <span style="font-weight: bold;">slow</span>.
+ You don't want to go too fast either, as this reduces the number of
+ samples per patch.<br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively historical X-Rite standard
+ (XRDI).<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP22"></a></span><span style="font-weight: bold;">DTP22
+ Digital Swatchbook reflective spectrometer</span><br>
+ <span style="font-weight: bold;"><br>
+ <img alt="" src="DTP22.jpg" style="width: 222px; height: 193px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP22</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. It is
+ capable of reading colored patches one at a time.<br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively historical X-Rite standard
+ (XRDI).<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP41"></a>DTP41 reflective, DTP41T
+ reflective/transmissive spectrometers<br>
+ <br>
+ <img alt="" src="DTP41.jpg" style="width: 263px; height: 298px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP41</span> and <span
+ style="font-weight: bold;">DTP41T</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. <br>
+ <br>
+ The series II instruments (<span style="font-weight: bold;">DTP41B</span>
+ and <span style="font-weight: bold;">DTP41TB</span>) offer both
+ serial and USB connection. Note that currently only serial operation
+ using Argyll is possible with these instruments.<br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively historical X-Rite standard
+ (XRDI).<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <a name="dtp51"></a><span style="font-weight: bold;">DTP51
+ reflective colorimeter<br>
+ <br>
+ <img alt="" src="DTP51.jpg" style="width: 263px; height: 223px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP51</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. <br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"><br>
+ </span></span>The DTP51's switch is triggered by inserting a strip
+ into the slot.<br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively historical X-Rite standard
+ (XRDI).<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP92"></a>DTP92 CRT display colorimeter<br>
+ <br>
+ <img alt="" src="DTP92.jpg" style="width: 223px; height: 180px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP92</span><span
+ style="font-weight: bold;"></span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. It will
+ only read CRT technology displays.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -1778,32 +2083,43 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type [Default, CB2].<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="DTP94"></a>DTP94, </span><font
- size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro" <span
- style="font-weight: bold;">display colorimetrers</span><br>
- <span style="font-weight: bold;"><br>
- <img title="DTP94" alt="" src="DTP94.jpg" style="width: 138px;
- height: 171px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; <img alt="" title="Optix XR/Pro" src="moxxr.jpg"
- style="width: 155px; height: 190px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP94 </span>from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument, although it is still being supplied to OEMs.&nbsp; It
- may still be available as old stock, or second hand. It was sold as
- an instrument without software as the DTP94, and packaged with
- software from the manufacturer as the "Optix XR" range.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type [Default, CB2].<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="DTP94"></a>DTP94, </span><font
+ size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro" <span
+ style="font-weight: bold;">display colorimetrers</span><br>
+ <span style="font-weight: bold;"><br>
+ <img title="DTP94" alt="" src="DTP94.jpg" style="width: 138px;
+ height: 171px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; <img alt="" title="Optix XR/Pro" src="moxxr.jpg"
+ style="width: 155px; height: 190px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP94 </span>from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument, although it is still being supplied to OEMs.&nbsp; It
+ may still be available as old stock, or second hand. It was sold as
+ an instrument without software as the DTP94, and packaged with
+ software from the manufacturer as the "Optix XR" range.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1847,8 +2163,19 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display, that is of the Non-Refresh type [default, CB1].<br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type [default, CB1].<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -1897,23 +2224,34 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type [CB2].<br>
- &nbsp;&nbsp;&nbsp; <b>g</b>&nbsp;&nbsp;&nbsp;
- Generic&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Generic
- display [CB3]<br>
- &nbsp;&nbsp; <br>
- <br>
- <span style="font-weight: bold;"></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="sl"></a>Spectrolino reflective/emissive spectrometer<br>
- <br>
- <img alt="" src="sl.jpg" style="width: 239px; height: 200px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type [CB2].<br>
+ &nbsp;&nbsp;&nbsp; <b>g</b>&nbsp;&nbsp;&nbsp;
+ Generic&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Generic
+ display [CB3]<br>
+ &nbsp;&nbsp; <br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="sl"></a>Spectrolino reflective/emissive spectrometer<br>
+ <br>
+ <img alt="" src="sl.jpg" style="width: 239px; height: 200px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
</span>The <span style="font-weight: bold;">Spectrolino </span>from
Gretag
@@ -1963,225 +2301,272 @@ Gretag
- MacBeth (Now X-Rite) is a discontinued instrument. It is often
- available second hand. If buying it second hand, make sure it comes
- with all it's accessories, including white reference, spot reading
- adapter, display reading adapters, filters (UV, polarizing, D65),
- serial cable adapter and power supply.<br>
- <span style="font-weight: bold;"><br>
- </span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="ss"></a>SpectroScan reflective/emissive and SpectroScanT
- reflective/emissive/transmissive spectrometers<br>
- <br>
- <img style="width: 336px; height: 294px;" alt="" src="ss.jpg"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">SpectroScan</span> and
- <span style="font-weight: bold;">SpectroScanT</span> from Gretag
- MacBeth (Now X-Rite) is a discontinued instrument. It is the
- combination of an X-Y table and the <span style="font-weight:
- bold;">Spectrolino</span> instrument. The <span
- style="font-weight: bold;">SpectroScanT</span> is capable of
- measuring transparency. It is often available second hand. If buying
- it second hand, make sure it comes with all it's accessories,
- including white reference, spot reading adapter, display reading
- adapters, filters (UV, polarizing, D65) and power supply.<br>
- <br>
- If measuring transparencies using a SpectroScanT, the <b>Enter</b>
- key on the instrument may be used to trigger each reading. It will
- be recognized after each previous reading has been completed.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <br>
- <span style="font-weight: bold;"><a name="i1p2"></a>Eye-One Pro2:</span><br>
- <img style=" width: 357px; height: 234px;" alt="Eye-One Pro 2"
- src="i1pro2.jpg"><br>
- <br>
- There is support for some of the new features of the Eye-One Pro2
- (also known as the Eye-One Pro Rev E), in particular the&nbsp; Rev E
- measurement mode, spectrometer stray light reduction, wavelength
- calibration, and improved black level tracking. This new support can
- be disabled and an Eye-One Pro2 operated in legacy mode by setting
- the environment variable ARGYLL_DISABLE_I1PRO2_DRIVER. See <a
- href="instruments.html#i1p">Eye-One Pro reflective/emissive
- spectrometer</a><span style="font-weight: bold;"> </span>below
- for details on the operation of this type of instrument.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="i1p"></a>Eye-One Pro and
- Eye-One Pro2 reflective/emissive spectrometer<br>
- <br>
- <img alt="" src="i1p.jpg" style="width: 347px; height: 234px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Eye-One Pro</span> from
- <a href="http://www.xrite.com/">X-Rite</a> (was Gretag MacBeth) is
- available in two packages from the manufacturer. These packages
- differ partly in what accessories come with the instrument, but
- primarily in what features the manufacturers software provides. This
- comparison <a
- href="http://www.xrite.com/product_overview.aspx?ID=812">chart</a>
- illustrates the differences. Used with Argyll, there are no
- differences in operation of an Eye-One Pro instrument, irrespective
- of which package it came with. The lowest cost package is the <a
- href="http://www.xrite.com/product_overview.aspx?ID=1461">i1 Basic
- Pro</a>.<br>
- <br>
- The EFI ES-1000 (which is a re-badged Eye-One Pro) is also reported
- to work with Argyll.<br>
- <br>
- Unless you know what you're doing, and have a very specific reason
- to buy an instrument fitted with a UV (Ultra Violet) filter, make
- sure that you buy an instrument without the filter. A UV filtered
- instrument can't deal intelligently with FWA (Fluorescent Whitener
- Additive) effects in paper. (Look <a href="FWA.html">here</a> for
- more information about FWA compensation.) Using FWA compensation you
- can make measurements using ISO 13655:2009 M0, M1 and M2 conditions.
- The M2 condition emulates a UV cut instrument.<br>
- <br>
- There have been four revisions of the Eye-One Pro, Rev. A, B, D and
- E (AKA Eye-One Pro2). The rev B, D and E are capable of sampling
- twice as fast as the Rev. A version of the instrument, and are also
- available with an ambient light reading capability.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> for those running on
- older versions of Linux with a Rev. D, there was a problem with the
- Linux USB stack that causes the instrument to stop working once it
- has been used. The only workaround is to unplug and replug the
- instrument in again, whereupon it can be used one time again. A fix
- for this problem was in the&nbsp; Linux 2.6.26 kernel release.<br>
- <br>
- See also <a href="i1proDriver.html">How can I have confidence in
- the i1pro Driver ?</a><br>
- <br>
- <span style="font-weight: bold;">Patch recognition:</span><br>
- <br>
- For the best chances of good patch recognition, the instrument
- should be drawn smoothly and not too rapidly over the strip. If
- there is a misread, try slowing down slightly. The Rev A and B.
- instruments have a slower sampling rate than the latter revision
- instruments, and hence must be used a bit more slowly. Generally a
- higher quality set of readings will result if slower scans are used,
- since there will then be more samples averaged for each patch.<br>
- <br>
- In <a href="chartread.html">chartread</a>, the -<span
- style="font-weight: bold;">T ratio</span> argument modifies the
- patch consistency tolerance threshold for the Eye-One Pro. In
- recognizing patches in a strip, the instrument takes multiple
- readings as the strip is read, and then divide the readings up into
- each patch. It then check the consistency of the multiple readings
- corresponding to each patch, and reject the measurement if they are
- too inconsistent. For some media (ie. a coarser screens, fabric
- etc.) the default tolerance may be unreasonably tight, so the <span
- style="font-weight: bold;">-T ratio</span> argument can be used to
- modify this criteria. To loosen the tolerance, use a number greater
- than 1.0 (ie. 1.5, 2.0). <span style="font-weight: bold;"></span><br>
- <br>
- <span style="font-weight: bold;">Special features:</span><br>
- <br>
- A feature unique to Argyll when used with the Eye-One Pro, is the
- high resolution spectral mode. This returns spectral measurements at
- 3.333 nm spacing, rather than the default 10nm spacing, and also
- extends the range of wavelengths very slightly. This high resolution
- may assist in giving better accuracy for "peaky" emissive sources
- such as illuminants and displays. The high resolution mode is
- selected by using the <span style="font-weight: bold;">-H</span>
- flag on the command line to <span style="font-weight: bold;">dispcal</span>,
- <span style="font-weight: bold;">dispread</span>, <span
- style="font-weight: bold;">chartread</span>, and <span
- style="font-weight: bold;">spotread</span>. It can also be toggled
- on and off within <span style="font-weight: bold;">spotread</span>
- using the <span style="font-weight: bold;">h</span> key.<br>
- <br>
- Note that while finer spectral resolution will worsen the signal to
- noise ratio of the individual spectral values, the signal to noise
- ratio of the resulting tri-stimulus color values will be identical
- to normal resolution mode, since the same overall integration is
- performed. <br>
- <br>
- See <a href="i1proHiRes.html">Does the i1pro High Resolution mode
- improve accuracy ?</a><br>
- <br>
- <img alt="High res. and standard res. spectrum."
- src="Fluorescent.jpg" style="width: 750px; height: 375px;"><br>
- <br>
- <img alt="C.R.T high res. and standard res. spectrum."
- src="CRTspectrum.jpg" style="width: 750px; height: 375px;"><br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="i1m"></a>Eye-One Monitor
- emissive spectrometer<br>
- <br>
- <img alt="" src="i1m.jpg" style="width: 347px; height: 234px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Eye-One Monitor</span>
- from <a href="http://www.xrite.com/">X-Rite</a> (was Gretag
- MacBeth) is a discontinued instrument. It was a lower cost version
- of the <span style="font-weight: bold;">Eye-One Pro</span> without
- reflective measurement capability. See <a href="#i1p">Eye-One Pro
- reflective/emissive spectrometer</a><span style="font-weight:
- bold;"> </span>for details on the operation of this instrument.<br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="i1d"></a>Eye-One Display
- 1, Eye-One Display 2, Eye-One Display LT, ColorMunki Create,
- ColorMunki Smile colorimeters,<br>
- <br>
- <img style=" width: 124px; height: 168px;" alt="ColorMunki Smile"
- src="Smile.jpg"><img alt="Eye-One Display 2" src="i1d.jpg"
- style="width: 145px; height: 168px;"> <img style="width: 133px;
- height: 168px;" alt="ColorMunki Create"
- src="ColorMunkiCreate.jpg"><br>
- <br>
- Instrument Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">ColorMunki Smile</span>
- colorimeter is a currently available instrument.<br>
- The <span style="font-weight: bold;">Eye-One Display LT</span> and
- <span style="font-weight: bold;">Eye-One Display 2</span> are
- discontinued products, although they may still be available from
- some retailers, second hand, and may still be shipped with some
- displays as part of their calibration capability.<br>
- The <span style="font-weight: bold;">ColorMunki Create</span>
- colorimeter is a discontinued product, although they may still be
- available from some retailers or second hand,can also be used. They
- will appear as an i1Display2 colorimeter.<br>
- The <span style="font-weight: bold;">HP DreamColor</span>
- colorimeter can also be used, and will appear as an i1Display2
- colorimeter [note that it is calibrated for the DreamColor display].<br>
- The <span style="font-weight: bold;">HP APS</span> (Advanced
- Profiling Solution) colorimeter is also reported to work, and will
- appear as an i1Display2.<br>
- The <span style="font-weight: bold;">CalMAN X2</span> colorimeter
- is also reported to work, and will appear as an i1Display2
- colorimeter.<br>
- The&nbsp; <span style="font-weight: bold;">Lacie Blue Eye</span> <span
- style="font-weight: bold;"></span> colorimeter is also reported to
- work, and will appear as an i1Display2 colorimeter.<br>
- <br>
- <span style="font-weight: bold;"></span>The <span
- style="font-weight: bold;">Eye-One Display 1</span> is a
- discontinued instrument. <br>
- <br>
- The Eye-One Display LT came with a less expensive<span
- style="text-decoration: underline;"></span> package with more
- limited software from the manufacture.<br>
- The Eye-One Display 2 package came with more software
- features,&nbsp; but the instruments are virtually identical, and
- will operate identically using Argyll.<br>
- The ColorMunki Create<span style="text-decoration: underline;"></span>
- package is another alternative, and will operate identically using
- Argyll.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ MacBeth (Now X-Rite) is a discontinued instrument. It is often
+ available second hand. If buying it second hand, make sure it comes
+ with all it's accessories, including white reference, spot reading
+ adapter, display reading adapters, filters (UV, polarizing, D65),
+ serial cable adapter and power supply.<br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively historical Gretag MacBeth
+ standard (GMDI).<br>
+ <span style="font-weight: bold;"><br>
+ </span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="ss"></a>SpectroScan reflective/emissive and SpectroScanT
+ reflective/emissive/transmissive spectrometers<br>
+ <br>
+ <img style="width: 336px; height: 294px;" alt="" src="ss.jpg"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">SpectroScan</span> and
+ <span style="font-weight: bold;">SpectroScanT</span> from Gretag
+ MacBeth (Now X-Rite) is a discontinued instrument. It is the
+ combination of an X-Y table and the <span style="font-weight:
+ bold;">Spectrolino</span> instrument. The <span
+ style="font-weight: bold;">SpectroScanT</span> is capable of
+ measuring transparency. It is often available second hand. If buying
+ it second hand, make sure it comes with all it's accessories,
+ including white reference, spot reading adapter, display reading
+ adapters, filters (UV, polarizing, D65) and power supply.<br>
+ <br>
+ If measuring transparencies using a SpectroScanT, the <b>Enter</b>
+ key on the instrument may be used to trigger each reading. It will
+ be recognized after each previous reading has been completed.<br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively historical Gretag MacBeth
+ standard (GMDI).<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <br>
+ <span style="font-weight: bold;"><a name="i1p2"></a>Eye-One Pro2:</span><br>
+ <img style=" width: 357px; height: 234px;" alt="Eye-One Pro 2"
+ src="i1pro2.jpg"><br>
+ <br>
+ <span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span> The <span style="font-weight: bold;">Eye-One Pro2 </span>(AKA
+
+
+ Eye-One Pro Rev E) from&nbsp;<a
+ href="http://www.kleininstruments.com/"></a> <a
+ href="http://www.xrite.com/">X-Rite</a> is a currently available
+ instrument. It is available in several packages from the
+ manufacturer. These packages differ partly in what accessories come
+ with the instrument, but primarily in what features the
+ manufacturers software provides. This comparison <a
+ href="http://www.xrite.com/product_overview.aspx?ID=812">chart</a>
+ illustrates the differences. Used with Argyll, there are no
+ differences in operation of an Eye-One Pro instrument, irrespective
+ of which package it came with. The lowest cost package is the <a
+href="http://www.xrite.com/categories/calibration-profiling/i1basic-pro-2">i1
+
+
+ Basic Pro 2</a>.<br>
+ <br>
+ There is support for some of the new features of the Eye-One Pro2
+ (also known as the Eye-One Pro Rev E), in particular the&nbsp; Rev E
+ measurement mode, spectrometer stray light reduction, wavelength
+ calibration, and improved black level tracking. This new support can
+ be disabled and an Eye-One Pro2 operated in legacy mode by setting
+ the environment variable ARGYLL_DISABLE_I1PRO2_DRIVER. See <a
+ href="instruments.html#i1p">Eye-One Pro reflective/emissive
+ spectrometer</a><span style="font-weight: bold;"> </span>below
+ for details on the operation of this type of instrument.<br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively X-Rite <a
+ href="http://www.xrite.com/xrite-graphic-arts-standard">XRGA</a>.<span
+ style="font-weight: bold;"></span><br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1p"></a>Eye-One Pro and
+ Eye-One Pro2 reflective/emissive spectrometer<br>
+ <br>
+ <img alt="" src="i1p.jpg" style="width: 347px; height: 234px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Eye-One Pro</span> from
+ <a href="http://www.xrite.com/">X-Rite</a> (was Gretag MacBeth) is a
+ discontinued instrument.<br>
+ <br>
+ The EFI ES-1000 (which is a re-badged Eye-One Pro) is also reported
+ to work with Argyll.<br>
+ <br>
+ Unless you know what you're doing, and have a very specific reason
+ to buy an instrument fitted with a UV (Ultra Violet) filter, make
+ sure that you buy an instrument without the filter. A UV filtered
+ instrument can't deal intelligently with FWA (Fluorescent Whitener
+ Additive) effects in paper. (Look <a href="FWA.html">here</a> for
+ more information about FWA compensation.) Using FWA compensation you
+ can make measurements using ISO 13655:2009 M0, M1 and M2 conditions.
+ The M2 condition emulates a UV cut instrument.<br>
+ <br>
+ There have been four revisions of the Eye-One Pro, Rev. A, B, D and
+ E (AKA Eye-One Pro2 - see above). The rev B, D and E are capable of
+ sampling twice as fast as the Rev. A version of the instrument, and
+ are also available with an ambient light reading capability.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> for those running on
+ older versions of Linux with a Rev. D, there was a problem with the
+ Linux USB stack that causes the instrument to stop working once it
+ has been used. The only workaround is to unplug and replug the
+ instrument in again, whereupon it can be used one time again. A fix
+ for this problem was in the&nbsp; Linux 2.6.26 kernel release.<br>
+ <br>
+ See also <a href="i1proDriver.html">How can I have confidence in
+ the i1pro Driver ?</a><br>
+ <br>
+ <span style="font-weight: bold;">Patch recognition:</span><br>
+ <br>
+ For the best chances of good patch recognition, the instrument
+ should be drawn smoothly and not too rapidly over the strip. If
+ there is a misread, try slowing down slightly. The Rev A and B.
+ instruments have a slower sampling rate than the latter revision
+ instruments, and hence must be used a bit more slowly. Generally a
+ higher quality set of readings will result if slower scans are used,
+ since there will then be more samples averaged for each patch.<br>
+ <br>
+ In <a href="chartread.html">chartread</a>, the -<span
+ style="font-weight: bold;">T ratio</span> argument modifies the
+ patch consistency tolerance threshold for the Eye-One Pro. In
+ recognizing patches in a strip, the instrument takes multiple
+ readings as the strip is read, and then divide the readings up into
+ each patch. It then check the consistency of the multiple readings
+ corresponding to each patch, and reject the measurement if they are
+ too inconsistent. For some media (ie. a coarser screens, fabric
+ etc.) the default tolerance may be unreasonably tight, so the <span
+ style="font-weight: bold;">-T ratio</span> argument can be used to
+ modify this criteria. To loosen the tolerance, use a number greater
+ than 1.0 (ie. 1.5, 2.0). <span style="font-weight: bold;"></span><br>
+ <br>
+ <b>Native Calibration Standard:</b><br>
+ <br>
+ Reflection measurements are natively historical Gretag MacBeth
+ standard (GMDI) for RevA-D,<br>
+ and&nbsp; natively X-Rite <a
+ href="http://www.xrite.com/xrite-graphic-arts-standard">XRGA</a>
+ for Rev E.<br>
+ <br>
+ <span style="font-weight: bold;">Special features:</span><br>
+ <br>
+ A feature unique to Argyll when used with the Eye-One Pro, is the
+ high resolution spectral mode. This returns spectral measurements at
+ 3.333 nm spacing, rather than the default 10nm spacing, and also
+ extends the range of wavelengths very slightly. This high resolution
+ may assist in giving better accuracy for "peaky" emissive sources
+ such as illuminants and displays. The high resolution mode is
+ selected by using the <span style="font-weight: bold;">-H</span>
+ flag on the command line to <span style="font-weight: bold;">dispcal</span>,
+ <span style="font-weight: bold;">dispread</span>, <span
+ style="font-weight: bold;">chartread</span>, and <span
+ style="font-weight: bold;">spotread</span>. It can also be toggled
+ on and off within <span style="font-weight: bold;">spotread</span>
+ using the <span style="font-weight: bold;">h</span> key.<br>
+ <br>
+ Note that while finer spectral resolution will worsen the signal to
+ noise ratio of the individual spectral values, the signal to noise
+ ratio of the resulting tri-stimulus color values will be identical
+ to normal resolution mode, since the same overall integration is
+ performed. <br>
+ <br>
+ See <a href="i1proHiRes.html">Does the i1pro High Resolution mode
+ improve accuracy ?</a><br>
+ <br>
+ <img alt="High res. and standard res. spectrum."
+ src="Fluorescent.jpg" style="width: 750px; height: 375px;"><br>
+ <br>
+ <img alt="C.R.T high res. and standard res. spectrum."
+ src="CRTspectrum.jpg" style="width: 750px; height: 375px;"><br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1m"></a>Eye-One Monitor
+ emissive spectrometer<br>
+ <br>
+ <img alt="" src="i1m.jpg" style="width: 347px; height: 234px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Eye-One Monitor</span>
+ from <a href="http://www.xrite.com/">X-Rite</a> (was Gretag
+ MacBeth) is a discontinued instrument. It was a lower cost version
+ of the <span style="font-weight: bold;">Eye-One Pro</span> without
+ reflective measurement capability. See <a href="#i1p">Eye-One Pro
+ reflective/emissive spectrometer</a><span style="font-weight:
+ bold;"> </span>for details on the operation of this instrument.<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1d"></a>Eye-One Display
+ 1, Eye-One Display 2, Eye-One Display LT, ColorMunki Create,
+ ColorMunki Smile colorimeters,<br>
+ <br>
+ <img style=" width: 124px; height: 168px;" alt="ColorMunki Smile"
+ src="Smile.jpg"><img alt="Eye-One Display 2" src="i1d.jpg"
+ style="width: 145px; height: 168px;"> <img style="width: 133px;
+ height: 168px;" alt="ColorMunki Create"
+ src="ColorMunkiCreate.jpg"><br>
+ <br>
+ Instrument Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">ColorMunki Smile</span>
+ colorimeter is a currently available instrument.<br>
+ The <span style="font-weight: bold;">Eye-One Display LT</span> and
+ <span style="font-weight: bold;">Eye-One Display 2</span> are
+ discontinued products, although they may still be available from
+ some retailers, second hand, and may still be shipped with some
+ displays as part of their calibration capability.<br>
+ The <span style="font-weight: bold;">ColorMunki Create</span>
+ colorimeter is a discontinued product, although they may still be
+ available from some retailers or second hand,can also be used. They
+ will appear as an i1Display2 colorimeter.<br>
+ The <span style="font-weight: bold;">HP DreamColor</span>
+ colorimeter can also be used, and will appear as an i1Display2
+ colorimeter [note that it is calibrated for the DreamColor display].<br>
+ The <span style="font-weight: bold;">HP APS</span> (Advanced
+ Profiling Solution) colorimeter is also reported to work, and will
+ appear as an i1Display2.<br>
+ The <span style="font-weight: bold;">CalMAN X2</span> colorimeter
+ is also reported to work, and will appear as an i1Display2
+ colorimeter.<br>
+ The&nbsp; <span style="font-weight: bold;">Lacie Blue Eye</span> <span
+ style="font-weight: bold;"></span> colorimeter is also reported to
+ work, and will appear as an i1Display2 colorimeter.<br>
+ <br>
+ <span style="font-weight: bold;"></span>The <span
+ style="font-weight: bold;">Eye-One Display 1</span> is a
+ discontinued instrument. <br>
+ <br>
+ The Eye-One Display LT came with a less expensive<span
+ style="text-decoration: underline;"></span> package with more
+ limited software from the manufacture.<br>
+ The Eye-One Display 2 package came with more software
+ features,&nbsp; but the instruments are virtually identical, and
+ will operate identically using Argyll.<br>
+ The ColorMunki Create<span style="text-decoration: underline;"></span>
+ package is another alternative, and will operate identically using
+ Argyll.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
The Display Selections for the <span style="font-weight: bold;">ColorMunki
@@ -2215,12 +2600,23 @@ Gretag
- Smile</span> are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f</span>
- &nbsp;&nbsp; LCD with CCFL back-light&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses a Cold
- Cathode Fluorescent back lighting. [Default, CB1]<br>
+
+
+
+
+
+
+
+
+
+
+
+ Smile</span> are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f</span>
+ &nbsp;&nbsp; LCD with CCFL back-light&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses a Cold
+ Cathode Fluorescent back lighting. [Default, CB1]<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>&nbsp;&nbsp;&nbsp;
@@ -2252,12 +2648,23 @@ Gretag
- LCD with LED back-light&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses
- Light Emitting Diode back lighting.<br>
- <br>
- other instruments will offer:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD with LED back-light&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses
+ Light Emitting Diode back lighting.<br>
+ <br>
+ other instruments will offer:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2306,8 +2713,19 @@ Gretag
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -2356,54 +2774,68 @@ Gretag
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
- Cathode Ray Tube display, that is of the Refresh type. [CB2]<br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="i1d3"></a></span>&nbsp; <span
- style="font-weight: bold;">i1 DisplayPro and ColorMunki Display<span
- style="font-weight: bold;"> colorimeters (i1 Display 3)</span><br>
- <br>
- <img alt="i1 Display Pro" src="i1d3_1.jpg" style="width: 194px;
- height: 223px;"> <img style="width: 176px; height: 222px;"
- alt="ColorMunki Display" src="i1d3_2.jpg"><br>
- <br>
- Instrument Availability:<br>
- <br>
- </span>Both instruments are currently available..<br>
- <br>
- The ColorMunki Display is a less expensive <a
-href="http://xritephoto.com/ph_product_overview.aspx?id=1513&amp;catid=149">package</a>
- with more limited software from the manufacture, and takes a
- noticeably longer time to make most measurements (a minimum of 1
- second), but both instruments will take longer for very dark
- samples, and under these conditions the speed difference is less
- significant.<br>
- <br>
- The i1Display Pro <a
-href="http://xritephoto.com/ph_product_overview.aspx?id=1454&amp;catid=109">package</a>
- comes with i1Profiler, and the instrument is generally faster than
- the ColorMunki Display, but other than this and the software
- package, the instruments appear to be virtually identical. (Note
- though that the ColorMunki Display is <u>unable</u> to measure the
- refresh period, so is less repeatable in this mode than the
- i1Display Pro).<br>
- <br>
- Both instruments are capable of using CCSS (<a
- href="File_Formats.html#ccss">Colorimeter Calibration Spectral
- Sample</a>) files, and this also gives the instrument the
- capability of using a non-default standard observer. CCSS files can
- be created using the <a href="ccxxmake.html">ccxxmake</a> tool, and
- installed or translated from the .EDR files that are provided with
- the instrument CD using the <a href="oeminst.html">oeminst</a>
- utility using a spectrometer as a reference.<br>
- <br>
- There are some OEM versions of this instrument around too, and the <a
- href="http://www.spectracal.com/">SpectraCal OEM i1Display</a>, <a
- href="http://www.chromapure.com/">ChromaPure</a>, <a
- href="http://www.necdisplay.com/p/sensors/mdsvsensor3">NEC
- SpectraSensor Pro</a> and <a
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
+ Cathode Ray Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1d3"></a></span>&nbsp; <span
+ style="font-weight: bold;">i1 DisplayPro and ColorMunki Display<span
+ style="font-weight: bold;"> colorimeters (i1 Display 3)</span><br>
+ <br>
+ <img alt="i1 Display Pro" src="i1d3_1.jpg" style="width: 194px;
+ height: 223px;"> <img style="width: 176px; height: 222px;"
+ alt="ColorMunki Display" src="i1d3_2.jpg"><br>
+ <br>
+ Instrument Availability:<br>
+ <br>
+ </span>Both instruments are currently available.<br>
+ <br>
+ The ColorMunki Display is a less expensive <a
+href="http://xritephoto.com/ph_product_overview.aspx?id=1513&amp;catid=149">package</a>
+ with more limited software from the manufacture, and has hardware
+ that takes a noticeably longer time to make most measurements (a
+ minimum of 1 second), but both instruments will take longer for very
+ dark samples, and under these conditions the speed difference is
+ less significant. Because of the measurement speed limitation, the
+ measurement of display refresh rate and synchronization of its
+ measurements to a refresh display is not possible with the
+ ColorMunki Display. <br>
+ <br>
+ The i1Display Pro <a
+href="http://xritephoto.com/ph_product_overview.aspx?id=1454&amp;catid=109">package</a>
+ comes with i1Profiler, and the instrument is generally faster than
+ the ColorMunki Display, but other than this and the software
+ package, the instruments appear to be virtually identical. (Note
+ though that the ColorMunki Display is <u>unable</u> to measure the
+ refresh period, so is less repeatable in this mode than the
+ i1Display Pro).<br>
+ <br>
+ Both instruments are capable of using CCSS (<a
+ href="File_Formats.html#ccss">Colorimeter Calibration Spectral
+ Sample</a>) files, and this also gives the instrument the
+ capability of using a non-default standard observer. CCSS files can
+ be created using the <a href="ccxxmake.html">ccxxmake</a> tool, and
+ installed or translated from the .EDR files that are provided with
+ the instrument CD using the <a href="oeminst.html">oeminst</a>
+ utility using a spectrometer as a reference.<br>
+ <br>
+ There are some OEM versions of this instrument around too, and the <a
+ href="http://www.spectracal.com/">SpectraCal OEM i1Display</a>, <a
+ href="http://www.chromapure.com/">ChromaPure</a>, <a
+ href="http://www.necdisplay.com/p/sensors/mdsvsensor3">NEC
+ SpectraSensor Pro</a> and <a
href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
@@ -2425,83 +2857,105 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- DreamColor</a> instruments are also reported to work. They will
- appear as a be a the same as the i1Display Pro.<br>
- <span style="font-weight: bold;">[Note</span> that if you have an
- OEM version of this instrument, it's worth checking if they come
- with any extra .edr files, that can then be translated for use with
- ArgyllCMS using <a href="oeminst.html">oeminst</a>.]<br>
- <br>
- On MSWindows, if you have installed the Manufacturers applications,
- you may have to shut the i1Profiler tray application down before
- Argyll can open the instrument.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
- style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp; A
- non-refresh type display [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
- &nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh period
- is measured, and the integration time adjusted appropriately. [CB2]<br>
- <br>
- With the manufacturers .edr files &amp; reference Argyll .ccss files
- installed, the following selections are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
- style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
- non-refresh type display [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
- &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh
- period is measured, and the integration time adjusted appropriately.
- [CB2]<br>
- &nbsp;&nbsp;&nbsp; <b>c</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRT
- (Hitachi CM2112MET, Diamond View 1772ie)<br>
- &nbsp;&nbsp;&nbsp; <b>l</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
- IPS (CCFL AC EIZO HP with CORRECTION)<br>
- &nbsp;&nbsp;&nbsp; <b>L</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
- Wide Gamut IPS (WG CCFL NEC241 271)<br>
- &nbsp;&nbsp;&nbsp; <b>b&nbsp;</b>&nbsp;&nbsp;&nbsp;&nbsp; LCD RGB
- LED IPS (RGBLED HP SOYO)<br>
- &nbsp;&nbsp;&nbsp; <b>e</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD White
- LED IPS (WLED AC LG Samsung)<br>
- &nbsp;&nbsp;&nbsp; <b>p</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Projector
- (Marantz HP Panasonic Projectors Hybrid EDR)<br>
- <br>
- By default the integration time is adaptive, taking longer when the
- light level is low. This can be disabled and a fixed integration
- time used to gain maximum speed at the cost of greatly reduced low
- light accuracy, by using the -Y A flag.<br>
- <br>
- <b>Note when measuring CRT displays:<br>
- </b><br>
- The small magnet in the ambient light cover used to signal what
- position it is in, can interfere in the operation of the CRT
- display, particularly if the ambient cover is in it's natural
- position at 180 degrees away from the measuring lens. One way of
- minimizing this is to swing the cover down so that it touches the
- display adjacent to the lens, thereby moving the magnet away from
- the display surface. A more thorough but inconvenient way of
- avoiding this problem is to unclip the ambient light cover and slide
- it down the cable.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="Huey"></a>Huey colorimeter<br>
- <br>
- <img alt="" src="Huey.jpg" style="width: 128px; height: 202px;"><br>
- <br>
- Availability:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ DreamColor</a> instruments are also reported to work. They will
+ appear as a be a the same as the i1Display Pro.<br>
+ <span style="font-weight: bold;">[Note</span> that if you have an
+ OEM version of this instrument, it's worth checking if they come
+ with any extra .edr files, that can then be translated for use with
+ ArgyllCMS using <a href="oeminst.html">oeminst</a>.]<br>
+ <br>
+ On MSWindows, if you have installed the Manufacturers applications,
+ you may have to shut the i1Profiler tray application down before
+ Argyll can open the instrument.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
+ &nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh period
+ is measured, and the integration time adjusted appropriately. [CB2]<br>
+ <br>
+ With the manufacturers .edr files &amp; reference Argyll .ccss files
+ installed, the following selections are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
+ &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh
+ period is measured, and the integration time adjusted appropriately.
+ [CB2]<br>
+ &nbsp;&nbsp;&nbsp; <b>c</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRT
+ (Hitachi CM2112MET, Diamond View 1772ie)<br>
+ &nbsp;&nbsp;&nbsp; <b>l</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
+ IPS (CCFL AC EIZO HP with CORRECTION)<br>
+ &nbsp;&nbsp;&nbsp; <b>L</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
+ Wide Gamut IPS (WG CCFL NEC241 271)<br>
+ &nbsp;&nbsp;&nbsp; <b>b&nbsp;</b>&nbsp;&nbsp;&nbsp;&nbsp; LCD RGB
+ LED IPS (RGBLED HP SOYO)<br>
+ &nbsp;&nbsp;&nbsp; <b>e</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD White
+ LED IPS (WLED AC LG Samsung)<br>
+ &nbsp;&nbsp;&nbsp; <b>p</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Projector
+ (Marantz HP Panasonic Projectors Hybrid EDR)<br>
+ <br>
+ By default the integration time is adaptive, taking longer when the
+ light level is low. This can be disabled and a fixed integration
+ time used to gain maximum speed at the cost of greatly reduced low
+ light accuracy, by using the -Y A flag.<br>
+ <br>
+ <b>Note when measuring CRT displays:<br>
+ </b><br>
+ The small magnet in the ambient light cover used to signal what
+ position it is in, can interfere in the operation of the CRT
+ display, particularly if the ambient cover is in it's natural
+ position at 180 degrees away from the measuring lens. One way of
+ minimizing this is to swing the cover down so that it touches the
+ display adjacent to the lens, thereby moving the magnet away from
+ the display surface. A more thorough but inconvenient way of
+ avoiding this problem is to unclip the ambient light cover and slide
+ it down the cable.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="Huey"></a>Huey colorimeter<br>
+ <br>
+ <img alt="" src="Huey.jpg" style="width: 128px; height: 202px;"><br>
+ <br>
+ Availability:<br>
+ <br>
</span>The <span style="font-weight: bold;">Huey </span>and <b>Huey
- Pro</b> are discontinued instruments. They may still be available
- as old stock, or second hand. <br>
- <span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ Pro</b> are discontinued instruments. They may still be available
+ as old stock, or second hand. <br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2550,8 +3004,19 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -2600,33 +3065,44 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type. [CB2]<br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="mox"></a>MonacoOPTIX
- colorimeters<br>
- <br>
- <img alt="" src="mox.jpg" style="width: 115px; height: 147px;">
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <img alt="" src="Chroma4.jpg"
- style="width: 135px; height: 146px;"><br>
- <br>
- Instrument Availability:<br>
- </span><br>
- <span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">MonacoOPTIX</span> from
- Monaco Soft is a discontinued instrument.&nbsp; It may still be
- available as old stock, or second hand. It was sold packaged with
- software from the manufacturer. The Sequel Chroma 4 appears to be a
- similar instrument, and both seem to operate as if they were an
- Eye-One Display 1 using Argyll.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="mox"></a>MonacoOPTIX
+ colorimeters<br>
+ <br>
+ <img alt="" src="mox.jpg" style="width: 115px; height: 147px;">
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <img alt="" src="Chroma4.jpg"
+ style="width: 135px; height: 146px;"><br>
+ <br>
+ Instrument Availability:<br>
+ </span><br>
+ <span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">MonacoOPTIX</span> from
+ Monaco Soft is a discontinued instrument.&nbsp; It may still be
+ available as old stock, or second hand. It was sold packaged with
+ software from the manufacturer. The Sequel Chroma 4 appears to be a
+ similar instrument, and both seem to operate as if they were an
+ Eye-One Display 1 using Argyll.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -2675,8 +3151,19 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type.<br>
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type.<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2725,41 +3212,53 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display, that is of the Non-Refresh type.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="spyd2"></a>Spyder 2
- colorimeter<br>
- <br>
- <img alt="" src="Spyd2.jpg" style="width: 218px; height: 232px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Spyder 2 </span><span
- style="font-weight: bold;"></span>has been superseded by the
- Spyder 5, but may be available second hand.<br>
- [The Spyder 1 has also been reported as working, but this has not
- been confirmed.]<br>
- <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Operation:<br>
- </span><br>
- <span style="font-weight: bold;">Important Note </span>about the
- ColorVision Spyder 2 instrument support:<br>
- <br>
- This instrument cannot function without the driver software having
- access to the vendor supplied PLD firmware pattern for it.<br>
- This firmware is not provided with Argyll, since it is not available
- under a compatible license.<br>
- <br>
- The purchaser of a Spyder 2 instrument should have received a copy
- of this firmware along with their instrument, and should therefore
- be able to enable the Argyll driver for this instrument by using the
- <a href="oeminst.html">oeminst</a> tool.<span style="font-weight:
- bold;"></span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display or alternate Calibration, that is of the Non-Refresh
+ type.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd2"></a>Spyder 2
+ colorimeter<br>
+ <br>
+ <img alt="" src="Spyd2.jpg" style="width: 218px; height: 232px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder 2 </span><span
+ style="font-weight: bold;"></span>has been superseded by the
+ Spyder 5, but may be available second hand.<br>
+ [The Spyder 1 has also been reported as working, but this has not
+ been confirmed.]<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ <span style="font-weight: bold;">Important Note </span>about the
+ ColorVision Spyder 2 instrument support:<br>
+ <br>
+ This instrument cannot function without the driver software having
+ access to the vendor supplied PLD firmware pattern for it.<br>
+ This firmware is not provided with Argyll, since it is not available
+ under a compatible license.<br>
+ <br>
+ The purchaser of a Spyder 2 instrument should have received a copy
+ of this firmware along with their instrument, and should therefore
+ be able to enable the Argyll driver for this instrument by using the
+ <a href="oeminst.html">oeminst</a> tool.<span style="font-weight:
+ bold;"></span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2808,8 +3307,19 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; A Liquid Crystal
- Display, that is of the Non-Refresh type. [Default, CB1]<br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; A Liquid Crystal
+ Display, that is of the Non-Refresh type. [Default, CB1]<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -2858,133 +3368,144 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type. [CB2]<br>
- <br>
- <br>
- <span style="font-weight: bold;">Linux USB hub problems:<br>
- <br>
- </span>Note that the Spyder doesn't appear to operate at all well on
- Linux if attached to a secondary USB hub. You may have such a
- secondary hub built into your motherboard. If Argyll has difficulty
- in reliably talking to the Spyder, try connecting it directly to the
- computer rather than via a usb hub, or try using a USB port on your
- computer that connects directly to a root hub. This is probably due
- to a bug in the Linux EHCI driver, and a fix is due to appear in the
- Linux kernel sometime after July 2011. The name of the fix is "EHCI:
- fix direction handling for interrupt data toggles".<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="spyd3"></a>Spyder 3
- colorimeter<br>
- <br>
- <img style="width: 262px; height: 220px;" alt="Spyder3"
- src="Spyd3.jpg"> <img style="width: 193px; height: 220px;"
- alt="Spyder3Express" src="Spyd3x.jpg"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Spyder3Elite</span>, <span
- style="font-weight: bold;">Spyder3Pro</span> and <span
- style="font-weight: bold;">Spyder3Express</span> have being
- superseded by the Spyder 5, but may still stocked by some dealers,
- and may be available second hand. The <span style="font-weight:
- bold;">Spyder3Elite</span> and <span style="font-weight: bold;">Spyder3Pro</span>
- appear to be identical hardware with different software from the
- manufacturer. The <span style="font-weight: bold;">Spyder3Express</span>
- lacks the ambient sensor.<br>
- <br>
- [Note that this instrument doesn't seem particularly suited to
- measuring CRT displays, since it no longer seems to synchronise its
- readings to a CRT refresh, and you can no longer remove the LCD
- filter, reducing its sensitivity compared to the Spyder 2 in CRT
- mode. The Spyder 2 or one of the other instruments may be a better
- choice if you particularly need to measure CRTs or Refresh
- displays.]<br>
- <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Operation:<br>
- </span><br>
- The ambient light sensor can be used with the <span
- style="font-weight: bold;">Spyder3Elite</span> and <span
- style="font-weight: bold;">Spyder3Pro</span> instruments, but is
- only capable of monochrome readings.<span style="font-weight: bold;"><br>
- </span><br>
- The Display Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
- style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp; A
- non-refresh type display [Default, CB1]<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span>
- &nbsp;&nbsp;&nbsp; A refresh type display. [CB2]<br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="spyd4"></a>Spyder 4
- colorimeter<br>
- <br>
- <img style=" width: 262px; height: 220px;" alt="Spyder4"
- src="Spyd4.jpg"> <br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Spyder4Elite</span>, <span
- style="font-weight: bold;">Spyder4Pro</span> and <span
- style="font-weight: bold;">Spyder4Express</span> have being
- superseded by the Spyder 5, but may still stocked by some dealers,
- and may be available second hand.&nbsp; The <span
- style="font-weight: bold;">Spyder4Elite</span> and <span
- style="font-weight: bold;">Spyder4Pro</span> appear to be
- identical hardware with different software from the manufacturer.
- The <span style="font-weight: bold;">Spyder4Express</span> lacks
- the ambient sensor.<br>
- <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Operation:<br>
- </span><br>
- These instruments are capable of using using CCSS (<a
- href="File_Formats.html#ccss">Colorimeter Calibration Spectral
- Sample</a>) files, and this also gives the instrument the
- capability of using a non-default standard observer. CCSS files can
- be created using the <a href="ccxxmake.html">ccxxmake</a> tool
- using a spectrometer as a reference.<br>
- <br>
- <span style="font-weight: bold;">Important Note </span>about the
- DataColor Spyder 4 vendor display type/calibration support:<br>
- <br>
- This instrument does not have a full range of display type
- calibration selections available without the vendor supplied
- calibration data for it.<br>
- This calibration data is not provided with Argyll, since it is not
- available under a compatible license.<br>
- You can use CCSS files as an alternative (see above), or as the
- purchaser of a Spyder 4 instrument you should have received a copy
- of the calibration data along with the instrument, and should
- therefore be able to enable the full range of display type
- selections in Argyll by using the <a href="oeminst.html">oeminst</a>
- tool.<br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
- style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp; A non-refresh type display with a generic calibration
- [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
- style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
- refresh type display with a generic calibration.[CB2]<br>
- <br>
- The Display Selections for this instrument when the manufacturers
- calibration information has been installed is:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
- style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
- calibration [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
- style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
- calibration.[CB2]<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;">Linux USB hub problems:<br>
+ <br>
+ </span>Note that the Spyder doesn't appear to operate at all well on
+ Linux if attached to a secondary USB hub. You may have such a
+ secondary hub built into your motherboard. If Argyll has difficulty
+ in reliably talking to the Spyder, try connecting it directly to the
+ computer rather than via a usb hub, or try using a USB port on your
+ computer that connects directly to a root hub. This is probably due
+ to a bug in the Linux EHCI driver, and a fix is due to appear in the
+ Linux kernel sometime after July 2011. The name of the fix is "EHCI:
+ fix direction handling for interrupt data toggles".<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd3"></a>Spyder 3
+ colorimeter<br>
+ <br>
+ <img style="width: 262px; height: 220px;" alt="Spyder3"
+ src="Spyd3.jpg"> <img style="width: 193px; height: 220px;"
+ alt="Spyder3Express" src="Spyd3x.jpg"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder3Elite</span>, <span
+ style="font-weight: bold;">Spyder3Pro</span> and <span
+ style="font-weight: bold;">Spyder3Express</span> have being
+ superseded by the Spyder 5, but may still stocked by some dealers,
+ and may be available second hand. The <span style="font-weight:
+ bold;">Spyder3Elite</span> and <span style="font-weight: bold;">Spyder3Pro</span>
+ appear to be identical hardware with different software from the
+ manufacturer. The <span style="font-weight: bold;">Spyder3Express</span>
+ lacks the ambient sensor.<br>
+ <br>
+ [Note that this instrument doesn't seem particularly suited to
+ measuring CRT displays, since it no longer seems to synchronise its
+ readings to a CRT refresh, and you can no longer remove the LCD
+ filter, reducing its sensitivity compared to the Spyder 2 in CRT
+ mode. The Spyder 2 or one of the other instruments may be a better
+ choice if you particularly need to measure CRTs or Refresh
+ displays.]<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ The ambient light sensor can be used with the <span
+ style="font-weight: bold;">Spyder3Elite</span> and <span
+ style="font-weight: bold;">Spyder3Pro</span> instruments, but is
+ only capable of monochrome readings.<span style="font-weight: bold;"><br>
+ </span><br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
+ style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span>
+ &nbsp;&nbsp;&nbsp; A refresh type display. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd4"></a>Spyder 4
+ colorimeter<br>
+ <br>
+ <img style=" width: 262px; height: 220px;" alt="Spyder4"
+ src="Spyd4.jpg"> <br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder4Elite</span>, <span
+ style="font-weight: bold;">Spyder4Pro</span> and <span
+ style="font-weight: bold;">Spyder4Express</span> have being
+ superseded by the Spyder 5, but may still stocked by some dealers,
+ and may be available second hand.&nbsp; The <span
+ style="font-weight: bold;">Spyder4Elite</span> and <span
+ style="font-weight: bold;">Spyder4Pro</span> appear to be
+ identical hardware with different software from the manufacturer.
+ The <span style="font-weight: bold;">Spyder4Express</span> lacks
+ the ambient sensor.<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ These instruments are capable of using using CCSS (<a
+ href="File_Formats.html#ccss">Colorimeter Calibration Spectral
+ Sample</a>) files, and this also gives the instrument the
+ capability of using a non-default standard observer. CCSS files can
+ be created using the <a href="ccxxmake.html">ccxxmake</a> tool
+ using a spectrometer as a reference.<br>
+ <br>
+ <span style="font-weight: bold;">Important Note </span>about the
+ DataColor Spyder 4 vendor display type/calibration support:<br>
+ <br>
+ This instrument does not have a full range of display type
+ calibration selections available without the vendor supplied
+ calibration data for it.<br>
+ This calibration data is not provided with Argyll, since it is not
+ available under a compatible license.<br>
+ You can use CCSS files as an alternative (see above), or as the
+ purchaser of a Spyder 4 instrument you should have received a copy
+ of the calibration data along with the instrument, and should
+ therefore be able to enable the full range of display type
+ selections in Argyll by using the <a href="oeminst.html">oeminst</a>
+ tool.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
+ style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; A non-refresh type display with a generic calibration
+ [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
+ refresh type display with a generic calibration.[CB2]<br>
+ <br>
+ The Display Selections for this instrument when the manufacturers
+ calibration information has been installed is:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
+ calibration [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
+ calibration.[CB2]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3033,17 +3554,28 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- - normal gamut Liquid Crystal Display with standard Cold Cathode
- Fluorescent Lamp backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
- Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
- Display with Cold Cathode Fluorescent Lamps backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
- LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
- gamut Liquid Crystal Display with a White LED backlight.<br>
+
+
+
+
+
+
+
+
+
+
+
+ - normal gamut Liquid Crystal Display with standard Cold Cathode
+ Fluorescent Lamp backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
+ Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
+ Display with Cold Cathode Fluorescent Lamps backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
+ LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
+ gamut Liquid Crystal Display with a White LED backlight.<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">B</span>&nbsp;&nbsp;
@@ -3092,12 +3624,23 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
- Backlight - wide gamut Liquid Crystal Display with RGB LED
- backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
- Type 2
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
+ Backlight - wide gamut Liquid Crystal Display with RGB LED
+ backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+ Type 2
Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3146,37 +3689,6 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- - normal gamut Liquid Crystal Display with alternative Cold Cathode
- Fluorescent Lamp backlight (Laptop ?)<br>
- <br>
- The ambient light sensor can be used with the <span
- style="font-weight: bold;">Spyder4Elite</span> and <span
- style="font-weight: bold;">Spyder4Pro</span> instruments, but is
- only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="spyd5"></a>Spyder 5
- colorimeter<br>
- <br>
- <img style="width: 262px; height: 220px;" alt="Spyder4"
- src="Spyd5.jpg" width="449" height="350"> <br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Spyder5Elite</span>, <span
- style="font-weight: bold;">Spyder5Pro</span> and <span
- style="font-weight: bold;">Spyder5Express</span> are a currently
- available instruments. The <span style="font-weight: bold;">Spyder5Elite</span>
- and <span style="font-weight: bold;">Spyder5Pro</span> appear to be
- identical hardware with different software from the manufacturer.
- The <span style="font-weight: bold;">Spyder5Express</span> lacks
- the ambient sensor.<br>
- <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Operation:<br>
- </span><br>
- These instruments are capable of using using CCSS (<a
- href="File_Formats.html#ccss">Colorimeter
@@ -3184,51 +3696,85 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- Calibration Spectral Sample</a>) files, and this also gives the
- instrument the capability of using a non-default standard observer.
- CCSS files can be created using the <a
- href="ccxxmake.html">ccxxmake</a> tool
- using a spectrometer as a reference.<br>
- <br>
- <span style="font-weight: bold;">Important Note </span>about the
- DataColor Spyder 5 vendor display type/calibration support:<br>
- <br>
- This instrument does not have a full range of display type
- calibration selections available without the vendor supplied
- calibration data for it.<br>
- This calibration data is not provided with Argyll, since it is not
- available under a compatible license.<br>
- You can use CCSS files as an alternative (see above), or as the
- purchaser of a Spyder 5 instrument you should have received a copy
- of the calibration data along with the instrument or have been
- directed to download it from the manufacturers website, and should
- therefore be able to enable the full range of display type
- selections in Argyll by using the <a
- href="oeminst.html">oeminst</a> tool.<br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
- style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp; A non-refresh type display with a generic calibration
- [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
- style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
- refresh type display with a generic calibration.[CB2]<br>
- <br>
- The Display Selections for this instrument when the manufacturers
- calibration information has been installed is:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
- style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
- calibration [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
- style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
- calibration.[CB2]<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+
+
+
+
+ - normal gamut Liquid Crystal Display with alternative Cold Cathode
+ Fluorescent Lamp backlight (Laptop ?)<br>
+ <br>
+ The ambient light sensor can be used with the <span
+ style="font-weight: bold;">Spyder4Elite</span> and <span
+ style="font-weight: bold;">Spyder4Pro</span> instruments, but is
+ only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd5"></a>Spyder 5
+ colorimeter<br>
+ <br>
+ <img style="width: 262px; height: 220px;" alt="Spyder4"
+ src="Spyd5.jpg" width="449" height="350"> <br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder5Elite</span>, <span
+ style="font-weight: bold;">Spyder5Pro</span> and <span
+ style="font-weight: bold;">Spyder5Express</span> are a currently
+ available instruments. The <span style="font-weight: bold;">Spyder5Elite</span>
+ and <span style="font-weight: bold;">Spyder5Pro</span> appear to be
+ identical hardware with different software from the manufacturer.
+ The <span style="font-weight: bold;">Spyder5Express</span> lacks
+ the ambient sensor.<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ These instruments are capable of using using CCSS (<a
+ href="File_Formats.html#ccss">Colorimeter Calibration Spectral
+ Sample</a>) files, and this also gives the instrument the
+ capability of using a non-default standard observer. CCSS files can
+ be created using the <a href="ccxxmake.html">ccxxmake</a> tool
+ using a spectrometer as a reference.<br>
+ <br>
+ <span style="font-weight: bold;">Important Note </span>about the
+ DataColor Spyder 5 vendor display type/calibration support:<br>
+ <br>
+ This instrument does not have a full range of display type
+ calibration selections available without the vendor supplied
+ calibration data for it.<br>
+ This calibration data is not provided with Argyll, since it is not
+ available under a compatible license.<br>
+ You can use CCSS files as an alternative (see above), or as the
+ purchaser of a Spyder 5 instrument you should have received a copy
+ of the calibration data along with the instrument or have been
+ directed to download it from the manufacturers website, and should
+ therefore be able to enable the full range of display type
+ selections in Argyll by using the <a href="oeminst.html">oeminst</a>
+ tool.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
+ style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; A non-refresh type display with a generic calibration
+ [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
+ refresh type display with a generic calibration.[CB2]<br>
+ <br>
+ The Display Selections for this instrument when the manufacturers
+ calibration information has been installed is:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
+ calibration [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
+ calibration.[CB2]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3277,17 +3823,28 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- - normal gamut Liquid Crystal Display with standard Cold Cathode
- Fluorescent Lamp backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
- Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
- Display with Cold Cathode Fluorescent Lamps backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
- LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
- gamut Liquid Crystal Display with a White LED backlight.<br>
+
+
+
+
+
+
+
+
+
+
+
+ - normal gamut Liquid Crystal Display with standard Cold Cathode
+ Fluorescent Lamp backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
+ Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
+ Display with Cold Cathode Fluorescent Lamps backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
+ LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
+ gamut Liquid Crystal Display with a White LED backlight.<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">B</span>&nbsp;&nbsp;
@@ -3336,12 +3893,23 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
- Backlight - wide gamut Liquid Crystal Display with RGB LED
- backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
- Type 2
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
+ Backlight - wide gamut Liquid Crystal Display with RGB LED
+ backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+ Type 2
Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3390,22 +3958,33 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- - normal gamut Liquid Crystal Display with alternative Cold Cathode
- Fluorescent Lamp backlight (Laptop ?)<br>
- <br>
- The ambient light sensor can be used with the <span
- style="font-weight: bold;">Spyder5Elite</span> and <span
- style="font-weight: bold;">Spyder5Pro</span> instruments, but is
- only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"></span><br>
- <hr style="width: 100%; height: 2px;"><a name="HCFR"></a><span
- style="font-weight: bold;" class="titre">Colorimètre HCFR
- colorimeter<br>
- <br>
- <img alt="" src="HCFR.jpg" style="width: 203px; height: 194px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ - normal gamut Liquid Crystal Display with alternative Cold Cathode
+ Fluorescent Lamp backlight (Laptop ?)<br>
+ <br>
+ The ambient light sensor can be used with the <span
+ style="font-weight: bold;">Spyder5Elite</span> and <span
+ style="font-weight: bold;">Spyder5Pro</span> instruments, but is
+ only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"></span><br>
+ <hr style="width: 100%; height: 2px;"><a name="HCFR"></a><span
+ style="font-weight: bold;" class="titre">Colorimètre HCFR
+ colorimeter<br>
+ <br>
+ <img alt="" src="HCFR.jpg" style="width: 203px; height: 194px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
</span>The <span style="font-weight: bold;" class="titre">Colorimètre
@@ -3454,26 +4033,37 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- HCFR Probe</span> is a kit instrument from <span
- style="font-weight: bold;"></span> <a
- href="http://www.homecinema-fr.com/colorimetre/index_en.php">HCFR</a>.
- <br>
- <br>
- <span style="font-weight: bold;">OS X</span><br>
- <br>
- Please note the installation <a href="Installing_OSX.html#HCFR">instructions</a>.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
- The accuracy of this instrument does not seem to be comparable to
- the commercial instruments when used for measuring displays,
- particularly in the area of measuring dark colors, and I've seen the
- best results when used with a CRT display. It may well give good
- results in calibrating projectors, since this was what it was
- designed to do.<br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ HCFR Probe</span> is a kit instrument from <span
+ style="font-weight: bold;"></span> <a
+ href="http://www.homecinema-fr.com/colorimetre/index_en.php">HCFR</a>.
+ <br>
+ <br>
+ <span style="font-weight: bold;">OS X</span><br>
+ <br>
+ Please note the installation <a href="Installing_OSX.html#HCFR">instructions</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
+ The accuracy of this instrument does not seem to be comparable to
+ the commercial instruments when used for measuring displays,
+ particularly in the area of measuring dark colors, and I've seen the
+ best results when used with a CRT display. It may well give good
+ results in calibrating projectors, since this was what it was
+ designed to do.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3522,8 +4112,19 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display [Default].<br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display [Default].<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -3572,38 +4173,49 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display.<br>
- &nbsp;&nbsp;&nbsp; <b>R</b> &nbsp; Raw&nbsp;
- Reading&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Raw sensor readings,
- used for calibration [CB1]<br>
- <br>
- <hr style="width: 100%; height: 2px;"><a name="ColorHug"></a><span
- style="font-weight: bold;" class="titre">ColorHug<br>
- <br>
- <img alt="" src="ColorHug.jpg" style="width: 203px; height:
- 194px;" width="552" height="623"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;" class="titre">ColorHug</span>
- is a low cost display colorimeter instrument from <span
- style="font-weight: bold;"></span> <a
- href="http://www.hughski.com/">Hughski</a>. <br>
- ArgyllCMS will also work with the <a
- href="http://www.hughski.com/colorhug2.html">ColorHug2</a>.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
- Due to the nature of its sensor, the ColorHug accuracy is quite
- dependent on the instrument calibration matrix. (The <b>ColorHug2</b>
- is much more forgiving though). A custom .CCMX will greatly assist
- it's accuracy, although a workaround is to calibrate your display
- using its native white point, rather than aiming for some absolute
- white point such as D65.<br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display.<br>
+ &nbsp;&nbsp;&nbsp; <b>R</b> &nbsp; Raw&nbsp;
+ Reading&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Raw sensor readings,
+ used for calibration [CB1]<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><a name="ColorHug"></a><span
+ style="font-weight: bold;" class="titre">ColorHug<br>
+ <br>
+ <img alt="" src="ColorHug.jpg" style="width: 203px; height:
+ 194px;" width="552" height="623"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;" class="titre">ColorHug</span>
+ is a low cost display colorimeter instrument from <span
+ style="font-weight: bold;"></span> <a
+ href="http://www.hughski.com/">Hughski</a>. <br>
+ ArgyllCMS will also work with the <a
+ href="http://www.hughski.com/colorhug2.html">ColorHug2</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
+ Due to the nature of its sensor, the ColorHug accuracy is quite
+ dependent on the instrument calibration matrix. (The <b>ColorHug2</b>
+ is much more forgiving though). A custom .CCMX will greatly assist
+ it's accuracy, although a workaround is to calibrate your display
+ using its native white point, rather than aiming for some absolute
+ white point such as D65.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp; <b>l</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3622,7 +4234,18 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- LCD, CCFL Backlight [Default]<br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD, CCFL Backlight [Default]<br>
&nbsp;&nbsp; <b>c</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3642,7 +4265,18 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- CRT display<br>
+
+
+
+
+
+
+
+
+
+
+
+ CRT display<br>
&nbsp;&nbsp; <b>p</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3662,7 +4296,18 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- Projector<br>
+
+
+
+
+
+
+
+
+
+
+
+ Projector<br>
&nbsp;&nbsp; <b>e</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3681,7 +4326,18 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- LCD, White LED Backlight<br>
+
+
+
+
+
+
+
+
+
+
+
+ LCD, White LED Backlight<br>
&nbsp;&nbsp; <b>F</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3701,7 +4357,18 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- Factory matrix (For Calibration) [CB1]<br>
+
+
+
+
+
+
+
+
+
+
+
+ Factory matrix (For Calibration) [CB1]<br>
&nbsp;&nbsp;<b> R</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3721,31 +4388,53 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- Raw Reading (For Factory matrix Calibration) [CB2]<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
+
+
+
+
+
+
+
+
+
+
+
+ Raw Reading (For Factory matrix Calibration) [CB2]<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
<a name="SMCube"></a><span style="font-weight: bold;">Palette/SwatchMate
- Cube<br>
- <br>
- <img alt="SwatchMate Cube" src="SMCube.jpg" width="169"
- height="205"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The Cube from <a href="http://palette.com/cube.html">Palette/SwatchMate</a>
- is a currently available entry level Colorimeter, with <a
- href="http://www.argyllcms.com/doc2/smcube/smcube1.html">somewhat
- limited accuracy</a>. The ArgyllCMS driver provides two
- alternative calibrations that noticably <a
- href="http://www.argyllcms.com/doc2/smcube/smcube2.html">improve
- this accuracy</a>.<br>
- <br>
- The Calibration Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp; <b>m</b>
+
+
+
+
+
+
+
+
+
+
+
+ Cube<br>
+ <br>
+ <img alt="SwatchMate Cube" src="SMCube.jpg" width="169"
+ height="205"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The Cube from <a href="http://palette.com/cube.html">Palette/SwatchMate</a>
+ is a currently available entry level Colorimeter, with <a
+ href="http://www.argyllcms.com/doc2/smcube/smcube1.html">somewhat
+ limited accuracy</a>. The ArgyllCMS driver provides two
+ alternative calibrations that noticably <a
+ href="http://www.argyllcms.com/doc2/smcube/smcube2.html">improve
+ this accuracy</a>.<br>
+ <br>
+ The Calibration Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp; <b>m</b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3753,7 +4442,18 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- Matt surfaces [Default]<br>
+
+
+
+
+
+
+
+
+
+
+
+ Matt surfaces [Default]<br>
&nbsp;&nbsp; <b>g</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3773,8 +4473,19 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- Gloss surfaces<br>
- &nbsp;&nbsp; <b>N</b>
+
+
+
+
+
+
+
+
+
+
+
+ Gloss surfaces<br>
+ &nbsp;&nbsp; <b>N</b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3782,54 +4493,69 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
- Native Calibration<br>
- <br>
- <span style="font-weight: bold;">Operation:<br>
- </span><br>
- The Cube must be connected via USB for operation with ArgyllCMS, and
- can be connected either by USB or using Bluetooth LE when used with
- <a href="http://www.argyllpro.com.au/">ArgyllPRO ColorMeter</a> on
- capable Android devices.<br>
- <br>
- The Cube goes to sleep fairly rapidly and must be woken up by
- pressing the top of it before connecting via USB to be recognized by
- ArgyllCMS, although once connected, and with an ArgyllCMS utility
- running, it should stay awake.<br>
- <br>
- When connecting via Bluetooth to ColorMeter, the foreground
- application will be the one that connects to it.<br>
- <br>
- The ability to measure values into its own memory and recover them
- later is not supported, since it is not possible to use the
- ArgyllCMS calibrations with this feature.<br>
- <br>
- <span style="font-weight: bold;">Calibration:</span><br>
- <br>
- As well as the normal white calibration step, the ArgyllCMS driver
- offers two option supplemental calibration steps that can improve
- accuracy, but both require appropriate calibration conditions. You
- can use <a href="spotread.html">spotread</a> with the 'k' command
- to trigger this calibration.<br>
- <br>
- The <b>black calibration</b> requires a light trap, and the easiest
- way of providing this is to place the Cube in a location that is
- dark (i.e. not illuminated directly by any light) and some distance
- from any surface. A practical approach I have used is to place the
- measuring end in a thick black sock, and hide it from direct
- illumination while this calibration step is done.<br>
- <br>
- The <b>gloss calibration</b> requires a black glossy surface. I
- have used a paint catalog gloss paint black sample square for this,
- but some other completely black glossy surface of sufficient size
- such as a glossy black plastic item or a smooth surface painted in
- gloss black paint should also work.<br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+
+
+
+
+
+
+
+
+
+
+ Native Calibration<br>
+ <br>
+ The <b>Cube</b><b></b> makes use of the newer FTDI FT231XS Virtual
+ COM Port Drivers (VCP), that may need installing for your operating
+ system. See <a href="Installing.html">installation instructions</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ The Cube must be connected via USB for operation with ArgyllCMS, and
+ can be connected either by USB or using Bluetooth LE when used with
+ <a href="http://www.argyllpro.com.au/">ArgyllPRO ColorMeter</a> on
+ capable Android devices.<br>
+ <br>
+ The Cube goes to sleep fairly rapidly and must be woken up by
+ pressing the top of it before connecting via USB to be recognized by
+ ArgyllCMS, although once connected, and with an ArgyllCMS utility
+ running, it should stay awake.<br>
+ <br>
+ When connecting via Bluetooth to ColorMeter, the foreground
+ application will be the one that connects to it.<br>
+ <br>
+ The ability to measure values into its own memory and recover them
+ later is not supported, since it is not possible to use the
+ ArgyllCMS calibrations with this feature.<br>
+ <br>
+ <span style="font-weight: bold;">Calibration:</span><br>
+ <br>
+ As well as the normal white calibration step, the ArgyllCMS driver
+ offers two option supplemental calibration steps that can improve
+ accuracy, but both require appropriate calibration conditions. You
+ can use <a href="spotread.html">spotread</a> with the 'k' command
+ to trigger this calibration.<br>
+ <br>
+ The <b>black calibration</b> requires a light trap, and the easiest
+ way of providing this is to place the Cube in a location that is
+ dark (i.e. not illuminated directly by any light) and some distance
+ from any surface. A practical approach I have used is to place the
+ measuring end in a thick black sock, and hide it from direct
+ illumination while this calibration step is done.<br>
+ <br>
+ The <b>gloss calibration</b> requires a black glossy surface. I
+ have used a paint catalog gloss paint black sample square for this,
+ but some other completely black glossy surface of sufficient size
+ such as a glossy black plastic item or a smooth surface painted in
+ gloss black paint should also work.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/oeminst.html b/doc/oeminst.html
index d1daccd..b52f1f2 100644
--- a/doc/oeminst.html
+++ b/doc/oeminst.html
@@ -9,11 +9,11 @@
<body>
<h2><b>spectro/oeminst</b></h2>
<h3>Summary</h3>
- A special purpose tool that installs various Instruments
- Manufacturers support files to enable various instrument operations
- when used with Argyll, as well as install colorimeter calibration
- and spectral sample files so that they appear in the display type
- list (<b>-y</b> option).<br>
+ A special purpose tool that installs Instruments Manufacturers
+ support files to enable various instrument operations when used with
+ Argyll, as well as install colorimeter calibration and spectral
+ sample files so that they appear in the display type list (<b>-y</b>
+ option).<br>
For the Spyder 2, it can install the instrument manufacturers PLD
firmware pattern, which is necessary for it to operate.<br>
For the Spyder 4 or 5, it can enable the full range of manufacturers
@@ -39,6 +39,8 @@
+
+
Verbose</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -51,6 +53,8 @@
+
+
Don't install, show where files would be installed</span><br>
<span style="font-family: monospace;">&nbsp;-c
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -64,6 +68,8 @@
+
+
Don't install, save files to current directory</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-S
@@ -78,9 +84,14 @@
+
+
Specify the install scope u = user (def.), l = local system]</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;infile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Manufacturers setup.exe install file(s) or .dll(s) containing
+ install files</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;infile.[edr|ccss|ccmx]&nbsp;
@@ -91,17 +102,6 @@
- setup.exe CD install file(s) or .dll(s) containing install files</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;infile.[edr|ccss|ccmx]&nbsp;
-
-
-
-
-
-
-
-
EDR file(s) to translate and install or CCSS or CCMX files to
install</span><br style="font-family: monospace;">
@@ -116,6 +116,8 @@
+
+
</span><small><span style="font-family: monospace;">If no file is
provided, oeminst will look for the install CD.</span></small>
<h3></h3>
@@ -159,6 +161,8 @@
+
+
2</span> instrument cannot function without the presence of the
instrument vendors PLD firmware pattern for the device. This
firmware is not provided with Argyll, since it has not been made
@@ -196,6 +200,8 @@ href="http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html">XDG
+
+
Base Directory specifications</a> are used as a basis for
storing the file). Programs that access instruments such as&nbsp;
<span style="font-weight: bold;">spotread</span>, <span
@@ -224,6 +230,8 @@ href="http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html">XDG
+
+
4</span>&nbsp; or <u><b>Spyder 5</b></u> instrument does not
have the full range of vendor instrument calibration options
without the presence of the instrument vendors calibration
@@ -295,6 +303,8 @@ href="http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html">XDG
+
+
Base Directory specifications</a> are used as a basis for storing
the file). Programs that access instruments such as&nbsp; <span
style="font-weight: bold;">spotread</span>, <span
@@ -325,6 +335,11 @@ href="http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html">XDG
have to mount the CDROM manually, and give oeminst the path to the
CDROM setup/setup.exe file as the argument <span style="font-style:
italic;">inputfile</span>.<span style="font-weight: bold;"><br>
+ </span><br>
+ If you have not been provided with a CDROM, then you may be able to
+ download an MSWindows install package from the Manufacturers <b>website</b>,
+ and then run <b>oeminst</b> on that file.<span style="font-weight:
+ bold;"><br>
<br>
NOTE </span>that under <span style="font-weight: bold;">OS X
10.6</span> (Snow Leopard) and latter, you may need to run oeminst
diff --git a/doc/profcheck.html b/doc/profcheck.html
index a85e07e..079190c 100644
--- a/doc/profcheck.html
+++ b/doc/profcheck.html
@@ -30,6 +30,7 @@ Show
+
CIE94 delta E values</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-k
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -43,6 +44,7 @@ create
+
X3DOM visualization (iccprofile.x3d.html)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -53,6 +55,7 @@ Use
+
X3DOM axes<br>
&nbsp;-m&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Make
@@ -62,6 +65,7 @@ X3DOM
+
lines a minimum of 0.5<br style="font-family: monospace;">
</span><span style="font-family: monospace;">&nbsp;-e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Color
@@ -71,14 +75,17 @@ vectors
+
acording to delta E<br>
&nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Sort output by delta E<br>
&nbsp;-h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Plot a histogram of delta E's<br>
&nbsp;-P
de&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -94,6 +101,7 @@ Specify
+
a device value to sort against</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;-p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -104,6 +112,7 @@ Sort
+
device value by PCS/Lab target</span><br style="font-family:
monospace;">
&nbsp; <span style="font-family: monospace;">-f
@@ -115,6 +124,7 @@ Sort
+
M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or
file.sp]<br>
&nbsp;-i illum&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Choose
@@ -126,6 +136,7 @@ Sort
+
A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp</span><span
style="font-family: monospace;"></span><br style="font-family:
monospace;">
@@ -139,6 +150,7 @@ Sort
+
1931_2 </span></small><small><span style="font-family:
monospace;">(def.)</span></small><small><span
style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
@@ -174,7 +186,10 @@ Sort
<br>
The <b>-v</b> flag prints out extra information during the
checking. A value greater than 1 will print the color values of each
- test point.<br>
+ test point on a line. The line consists of:<br>
+ <b>[</b><i>Delta_E</i><b>]</b><i> Patch_no</i><b>:</b><i>&nbsp;
+ Device values </i><b>-&gt;</b><i> Profile PCS values </i><b>should
+ be</b><i> .ti3 PCS values</i><br>
<br>
The <b>-c</b> option causes the differences between the test values
and the profile prediction of the color for each device value to be
@@ -208,7 +223,8 @@ Sort
badly read patches.<br>
<br>
The <b>-h</b> flag will display a histogram plot of the fit delta
- E's. The X scale is delta E, the Y scale is %<br>
+ E's, as well as print each bin's details. The X scale is delta E,
+ the Y scale is % area of each bin.<br>
<br>
The <b>-P N.NN</b> option will create a pruned .ti3 file called
data_pN.NN that contains just the measurement points that have a fit
diff --git a/doc/spec2cie.html b/doc/spec2cie.html
index 7911948..2780161 100644
--- a/doc/spec2cie.html
+++ b/doc/spec2cie.html
@@ -1,7 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <title>fakeread</title>
+ <title>spec2cie</title>
<meta http-equiv="content-type" content="text/html;
charset=windows-1252">
<meta name="author" content="Graeme Gill">
@@ -9,38 +9,60 @@
<body>
<h2><b>spectro/</b><span style="text-decoration: underline;"></span>spec2cie</h2>
<h3>Summary</h3>
- Convert reflective spectral <a href="File_Formats.html#.ti3">.ti3</a>
- readings into CIE XYZ and D50 L*a*b* readings. Apply FWA, plot
- spectrums.<br>
+ Convert spectral <a href="File_Formats.html#.ti3">.ti3</a> or <a
+ href="File_Formats.html#.sp">.sp</a> readings into CIE XYZ and D50
+ L*a*b* readings. Apply FWA, plot spectrums.<br>
+ This is assumed to be for a reflective media by default - i.e. that
+ the input .ti3 or .sp file values are spectral reflectances, unless
+ the input is marked as <span style="font-weight: bold;">DEVICE_CLASS</span>&nbsp;
+
+
+ <span style="font-weight: bold;">EMISINPUT</span> (See the <a
+ href="ti3_format.html">description of the .ti3 format</a>. This
+ would have to be done manually, as no ArgyllCMS tools generate such
+ data.)<br>
<h3>Usage</h3>
- <tt><small>spec2cie [options] <span style="font-style: italic;">input.ti3
+ <tt><small>spec2cie [options] <span style="font-style: italic;">input.[ti3|sp]
- output.ti3<br>
+
+
+
+ output.[ti3|sp]<br>
&nbsp;</span></small></tt><tt><small>-v
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Verbose mode</small></tt><br>
<tt><small><small>&nbsp;<a href="spec2cie.html#I">-I <i>illum</i></a>&nbsp;&nbsp;
- &nbsp;&nbsp; Override actual instrument illuminant in .ti3
- file:<br>
+
+
+
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Override actual
+ instrument illuminant in .ti3 or .sp file:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp; &nbsp;&nbsp; A, C, D50, D50M2, D65, F5, F8, F10 or
- file.sp<br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A, C, D50, D50M2,
+ D65, F5, F8, F10 or file.sp<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
(only used in conjunction with <span style="font-weight:
bold;">-f</span>)<br>
</small></small></tt><tt><small><small>&nbsp;<a
- href="colprof.html#f">-f [<i>illum</i>]</a> &nbsp;&nbsp; Use
- Fluorescent Whitening Agent compensation [simulated inst.
- illum.:<br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ href="colprof.html#f">-f [<i>illum</i>]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use Fluorescent Whitening
+ Agent compensation [simulated inst. illum.:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
@@ -48,56 +70,61 @@
file.sp]<br>
</small></small></tt><tt><small><small><small>&nbsp;<a
href="spec2cie.html#i">-i <i>illum</i></a>&nbsp;&nbsp;
- &nbsp;&nbsp; Choose illuminant for computation of CIE XYZ
- from spectral data &amp; FWA:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Choose illuminant for
+ computation of CIE XYZ from spectral data &amp; FWA:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp; &nbsp;&nbsp;&nbsp; A, C, D50 (def.), D50M2, D65, F5,
- F8, F10 or file.sp<br>
+ &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A, C, D50
+ (def.), D50M2, D65, F5, F8, F10 or file.sp<br>
&nbsp;</small></small><a href="#o">-o <i>observ</i></a>&nbsp;
- &nbsp;&nbsp; Choose CIE Observer for spectral data:<br>
+
+
+
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Choose CIE Observer for
+ spectral data:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
-&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
1931_2 </small></tt><tt><small> (def.)</small></tt><tt><small>,
1964_10, S&amp;B 1955_2, shaw, J&amp;V 1978_2 or file.cmf<br>
- &nbsp;<a href="#p">-n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;<a href="#p">-n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Don't
output
- spectral values<br>
- </small></tt><tt><small>&nbsp;<a href="#p">-p</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Plot each values spectrum</small></tt><tt><br>
- </tt><tt> </tt><tt><small>&nbsp;<span style="font-style: italic;">input.ti3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Measurement
-
- file<br>
- &nbsp;<span style="font-style: italic;">output.ti3</span>&nbsp;&nbsp;&nbsp;&nbsp;
-
+ spectral values<br>
+ </small></tt><tt><small>&nbsp;<a href="#p">-p</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Converted measurement file</small></tt><br>
+ Plot each values spectrum</small></tt><tt><br>
+ </tt><tt> </tt><tt><small>&nbsp;<span style="font-style: italic;">input.[ti3|sp]</span>
+ &nbsp;&nbsp; Measurement file<br>
+ &nbsp;<span style="font-style: italic;">output.[ti3</span>|sp]
+ &nbsp; Converted measurement file</small></tt><br>
<h3>Comments</h3>
This program takes the (usually reflective) spectral data in a .ti3
- file, converts them to XYZ and D50 L*a*b* and fills the XYZ_[XYZ]
- and LAB_[LAB] columns in the output .ti3 file. If the columns
- XYZ_[XYZ] and/or LAB_[LAB] are missing in the input file, they are
- added to the output file.<br>
+ or .sp file, converts them to XYZ and D50 L*a*b* and fills the
+ XYZ_[XYZ] and LAB_[LAB] columns in the output .ti3 or .sp file. If
+ the columns XYZ_[XYZ] and/or LAB_[LAB] are missing in the input
+ file, they are added to the output file.<br>
<br>
If FWA correction is applied, then the spectra saved will be FWA
corrected, as well as the XYZ and D50 L*a*b* values.<br>
<br>
- All other columns are copied from the input to the output .ti3 file.<br>
+ All other columns are copied from the input to the output .ti3 or
+ .sp file.<br>
<br>
Setting an actual instrument/simulated instrument/CIE illuminant
only has an effect for reflective/transmissive spectra. Emissive
@@ -139,15 +166,18 @@ Measurement
+
+
+
<a href="colprof.html#f">colprof -f</a> for a fuller explanation. <br>
<br>
<a name="i"></a>The <b>-i</b> parameter allows specifying a
standard or custom illumination spectrum, applied to spectral .ti3
- data to compute PCS (Profile Connection Space) tristimulus values. <b>A</b>,
- <b>D50</b>, <b>D65</b>, <b>F5</b>, <b>F8</b>, <b>F10</b> are a
- selection of standard illuminant spectrums, with <b>D50</b> being
- the default. If a filename is specified instead, it will be assumed
- to be an Argyll specific <a href="File_Formats.html#.sp">.sp</a>
+ pr .sp data to compute PCS (Profile Connection Space) tristimulus
+ values. <b>A</b>, <b>D50</b>, <b>D65</b>, <b>F5</b>, <b>F8</b>,
+ <b>F10</b> are a selection of standard illuminant spectrums, with <b>D50</b>
+ being the default. If a filename is specified instead, it will be
+ assumed to be an Argyll specific <a href="File_Formats.html#.sp">.sp</a>
custom spectrum file. This only works if spectral data is available.
Illuminant details are:<br>
<br>
diff --git a/doc/spotread.html b/doc/spotread.html
index 3fe030f..36ee999 100644
--- a/doc/spotread.html
+++ b/doc/spotread.html
@@ -47,6 +47,15 @@
+
+
+
+
+
+
+
+
+
&nbsp; &nbsp; &nbsp; Verbose mode</span><br style="font-family:
monospace;">
<span style="font-family: monospace;"></span><span
@@ -80,6 +89,15 @@
+
+
+
+
+
+
+
+
+
&nbsp; &nbsp; &nbsp; Print spectrum for each reading.</span></small><br
style="font-family: monospace;">
<small><span style="font-family: monospace;"></span><span
@@ -118,6 +136,15 @@
+
+
+
+
+
+
+
+
+
Set COM port, 1..4 (default 1)</span><span style="font-family:
monospace;"></span><span style="font-family: monospace;"><br
style="font-family: monospace;">
@@ -150,6 +177,15 @@
+
+
+
+
+
+
+
+
+
&nbsp; &nbsp; &nbsp; Use transmission measurement mode</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a style="
@@ -182,6 +218,15 @@
+
+
+
+
+
+
+
+
+
Use emissive measurement mode (absolute results)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style=" font-family: monospace;" href="#eb">-eb</a><span
@@ -213,6 +258,15 @@
+
+
+
+
+
+
+
+
+
Use display white brightness relative measurement mode<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style=" font-family: monospace;" href="#ew">-ew</a><span
@@ -227,6 +281,15 @@
+
+
+
+
+
+
+
+
+
Use display white point relative chromatically adjusted mode<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style=" font-family: monospace;" href="#p">-p</a><span
@@ -258,6 +321,15 @@
+
+
+
+
+
+
+
+
+
Use telephoto measurement mode (absolute results)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style=" font-family: monospace;" href="#pb">-pb</a><span
@@ -289,6 +361,15 @@
+
+
+
+
+
+
+
+
+
Use </span></small><small><span style="font-family: monospace;">projector</span></small><small><span
style="font-family: monospace;"> white brightness relative
measurement mode<br>
@@ -322,6 +403,15 @@
+
+
+
+
+
+
+
+
+
Use </span></small><small><span style="font-family: monospace;">projector</span></small><small><span
style="font-family: monospace;"> </span></small><small><span
style="font-family: monospace;">white point relative
@@ -356,6 +446,15 @@
+
+
+
+
+
+
+
+
+
Use ambient measurement mode (absolute results)<br>
&nbsp;<a href="#f">-f</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -384,6 +483,15 @@
+
+
+
+
+
+
+
+
+
Use ambient flash measurement mode (absolute results)<br>
</span></small><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#y">-y X</a>
@@ -414,6 +522,15 @@
+
+
+
+
+
+
+
+
+
Display type - instrument specific list to choose from.</span></font><br>
<small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="spotread.html#I">-I illum</a><span
@@ -442,6 +559,15 @@ M0,
+
+
+
+
+
+
+
+
+
M1, M2, A, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp</span></small><br
style="font-family: monospace;">
<small><span style="font-family: monospace;"></span><span
@@ -487,6 +613,15 @@ D50
+
+
+
+
+
+
+
+
+
D50M2, D65, F5, F8, F10 or file.sp</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;</span><a style="
@@ -522,6 +657,15 @@ D50
+
+
+
+
+
+
+
+
+
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span></small><small><span
style="font-family: monospace;">1931_2 </span></small><small><span
style="font-family: monospace;"> (def.)</span></small><small><span
@@ -556,6 +700,15 @@ D50
+
+
+
+
+
+
+
+
+
Set filter configuration:<br>
&nbsp;&nbsp;
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -585,6 +738,15 @@ D50
+
+
+
+
+
+
+
+
+
None<br>
&nbsp;&nbsp;
p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -614,6 +776,15 @@ D50
+
+
+
+
+
+
+
+
+
Polarising filter<br>
&nbsp;&nbsp;
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -643,6 +814,15 @@ D50
+
+
+
+
+
+
+
+
+
D65<br>
&nbsp;&nbsp;
u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -672,9 +852,27 @@ D50
+
+
+
+
+
+
+
+
+
U.V. Cut<br>
&nbsp;<a href="#E">-E extrafilterfile</a>&nbsp;&nbsp;&nbsp;
Apply extra filter compensation file<br>
+ &nbsp;<a href="#A">-A N|A|X|G</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+ XRGA conversion (default N)<br>
</span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#x">-x</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -704,6 +902,15 @@ D50
+
+
+
+
+
+
+
+
+
Display Yxy instead of Lab<br>
</span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#h">-h</a>
@@ -734,6 +941,15 @@ D50
+
+
+
+
+
+
+
+
+
Display LCh instead of Lab</span></font><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#V">-V</a>
@@ -764,6 +980,15 @@ D50
+
+
+
+
+
+
+
+
+
Show running average and std. devation from ref.</span></font><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#T">-T</a>
@@ -794,6 +1019,15 @@ D50
+
+
+
+
+
+
+
+
+
Display correlated color temperatures, CRI and TLCI<br>
</span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -823,6 +1057,15 @@ D50
+
+
+
+
+
+
+
+
+
Disable initial calibration of instrument if possible</span></font><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="spotread.html#O">-O</a>
@@ -853,6 +1096,15 @@ D50
+
+
+
+
+
+
+
+
+
Do one cal. or measure and exit</span></font><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#H">-H</a><span
@@ -860,6 +1112,14 @@ D50
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode
(if available)<br>
+ &nbsp;<a href="#R">-R fname.sp</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+ Preset reference to spectrum<br>
&nbsp;</span></font><font size="-1"><span style="font-family:
monospace;"><a href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -888,6 +1148,15 @@ D50
+
+
+
+
+
+
+
+
+
Apply Colorimeter Correction Matrix</span></font><br>
<span style="font-family: monospace;">&nbsp;<a href="#X2">-X
file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -922,6 +1191,15 @@ Samples
+
+
+
+
+
+
+
+
+
for calibration</span><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
style=" font-family: monospace;" href="#Yrn">-<font size="-1">Y</font>
@@ -945,6 +1223,15 @@ Samples
+
+
+
+
+
+
+
+
+
&nbsp;&nbsp;&nbsp;&nbsp; Override refresh, non-refresh display
mode</span></font><br>
<tt>&nbsp;<a href="#YR">-Y R:<i>rate</i></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -958,6 +1245,15 @@ Samples
+
+
+
+
+
+
+
+
+
Override measured refresh rate with rate Hz</tt><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
style=" font-family: monospace;" href="#YA">-<font size="-1">Y </font>A</a><span
@@ -965,6 +1261,17 @@ Samples
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; Use non-adaptive integration time mode (if
available).</span></font><br>
+ <tt>&nbsp;<a href="#YW">-Y W:fname.sp</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+ Save white tile ref. spectrum to file</tt><br>
+ <tt>&nbsp;<a href="#YL">-Y L</a> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; Test for i1Pro Lamp
+ Drift, and remediate it</tt><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
@@ -1001,6 +1308,15 @@ none,
+
+
+
+
+
+
+
+
+
h = HW, x = Xon/Xoff</span></font><br>
<small><span style="font-family: monospace;">&nbsp;</span><a style="
font-family: monospace;" href="#D">-D [level]</a><span
@@ -1035,6 +1351,15 @@ none,
+
+
+
+
+
+
+
+
+
Optional file to save reading results<br style="font-family:
monospace;">
</span></font><small><span style="font-family: monospace;"></span><span
@@ -1061,10 +1386,10 @@ none,
The Graph plots light wavelength on the X axis, and either absolute
or relative level on the Y axis. <br>
<br>
- <table cellpadding="0" cellspacing="0" border="1" height="153"
- width="200">
+ <table border="1" cellpadding="0" cellspacing="0" width="200"
+ height="153">
</table>
- <table cellpadding="0" cellspacing="0" border="1">
+ <table border="1" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<th valign="top">&nbsp; Measurement Mode &nbsp; <br>
@@ -1073,20 +1398,29 @@ none,
</th>
</tr>
<tr>
- <td align="center" valign="top">Emission<br>
+ <td valign="top" align="center">Emission<br>
</td>
- <td align="center" valign="top">mW/(m<sup>2</sup>.sr.nm)</td>
+ <td valign="top" align="center">mW/(m<sup>2</sup>.sr.nm)</td>
</tr>
<tr>
- <td align="center" valign="top">Ambient<br>
+ <td valign="top" align="center">Ambient<br>
</td>
- <td align="center" valign="top">mW/(m<sup>2</sup>.nm)<br>
+ <td valign="top" align="center">mW/(m<sup>2</sup>.nm)<br>
</td>
</tr>
<tr>
- <td align="center" valign="top">Emission Flash<br>
+ <td valign="top" align="center">Emission Flash<br>
</td>
- <td align="center" valign="top">&nbsp; mW/(m<sup>2</sup>.sr.nm.s)
+ <td valign="top" align="center">&nbsp; mW/(m<sup>2</sup>.sr.nm.s)
+
+
+
+
+
+
+
+
+
@@ -1097,21 +1431,21 @@ none,
</td>
</tr>
<tr>
- <td align="center" valign="top">Ambient Flash<br>
+ <td valign="top" align="center">Ambient Flash<br>
</td>
- <td align="center" valign="top">mW/(m<sup>2</sup>.nm.s)<br>
+ <td valign="top" align="center">mW/(m<sup>2</sup>.nm.s)<br>
</td>
</tr>
<tr>
- <td align="center" valign="top">Reflective<br>
+ <td valign="top" align="center">Reflective<br>
</td>
- <td align="center" valign="top">%/nm<br>
+ <td valign="top" align="center">%/nm<br>
</td>
</tr>
<tr>
- <td align="center" valign="top">Transmissive<br>
+ <td valign="top" align="center">Transmissive<br>
</td>
- <td align="center" valign="top">%/nm<br>
+ <td valign="top" align="center">%/nm<br>
</td>
</tr>
</tbody>
@@ -1185,11 +1519,19 @@ none,
allows measuring in ambient illumination mode using instruments that
support this mode (i.e. Eye-One Display 2). Values returned are
absolute, and include the various color temperatures and Color
- Rendering Index (see <span style="font-weight: bold;">-T</span>).
+ Rendering Index (<a href="#T">see <span style="font-weight: bold;">-T</span></a>).
+
+
If the instrument does not support ambient mode, emissive mode will
be used instead. An adaptive integration time will be used in
devices that support it. <br>
<br>
+ For an instrument that supports it (i.e. the Emulated transmission
+ measurement mode of the JETI 1211), then using <b>-a</b> after the
+ <b>-t</b> switch will select the alternate 90/diffuse transmission
+ geometry (i.e. using the ambient adapter for transmission
+ measurement).<br>
+ <br>
<a name="f"></a>The <span style="font-weight: bold;">-f</span> flag
allows measuring a flash with those instruments that support
scanning emissive measurements. The instrument needs to be triggered
@@ -1223,13 +1565,10 @@ none,
reflectance instrument illuminant when FWA compensation is used
during <u>measurement</u>, overriding the default <b>D50</b> or
CIE computation illuminant used for FWA (see <b>-i</b> below<b>). </b>If
-
-
- using <b>M0</b>, <b>M1</b> or <b>M2</b>, then the <b>-i</b>
- option is <b>not</b> normally used. See <a href="colprof.html#f">colprof
-
-
- -f</a> for a fuller explanation. <br>
+ intending to use standard <b>M0</b>, <b>M1</b> or <b>M2</b>
+ conditions, then use just the <b>-I</b> option and not the&nbsp; <b>-i</b>
+ option. See <a href="colprof.html#f">colprof -f</a> for a fuller
+ explanation. <br>
<br>
<a name="i"></a>The <b>-i</b> parameter allows specifying a
standard or custom reflectance illumination spectrum applied to <span
@@ -1237,12 +1576,13 @@ none,
spectral data to <u>compute</u> CIE tristimulus values. <b>A</b>,
<b>D50</b>, <b>D50M2, D65</b>, <b>F5</b>, <b>F8</b>, <b>F10</b>
are a selection of standard illuminant spectrums, with <b>D50</b>
- being the default. If using <b>-I M0</b>, <b>M1</b> or <b>M2</b>,
- then this <b>-i</b> option is <b>not</b> normally used. If a
- filename is specified instead, it will be assumed to be an Argyll
- specific <a href="File_Formats.html#.sp">.sp</a> spectrum file. If
- FWA compensation is used during measurement, this illuminant will be
- used by default as the simulated instrument illuminant.<br>
+ being the default. If using <b>-I</b> to obtain standard <b>M0</b>,
+ <b>M1</b> or <b>M2</b> conditions, then this <b>-i</b> option is <b>not</b>
+ normally used. If a filename is specified instead, it will be
+ assumed to be an Argyll specific <a href="File_Formats.html#.sp">.sp</a>
+ spectrum file. If FWA compensation is used during measurement, this
+ illuminant will be used by default as the simulated instrument
+ illuminant.<br>
<br>
<a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
observer, and is used to compute PCS (Profile Connection Space)
@@ -1275,6 +1615,21 @@ none,
style="font-weight: bold;">Note</span> that this is currently only
supported by the Spectrolino driver.]<br>
<br>
+ <a name="A"></a>The <b>-A</b> options allows overriding the default
+ or environment variable set <a href="XRGA.html">XRGA</a>
+ conversion:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <b>-A N|A|X|G</b><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>N</b> argument sets
+ the calibration to Native (default).<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>A</b> argument sets
+ the calibration to XRGA.<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>X</b> argument sets
+ the calibration to XRDI.<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; The <b>G</b> argument sets
+ the calibration to GMDI.<br>
+ <br>
<a name="x"></a>The <b>-x</b> option causes the reading to be
displayed as XYZ and Yxy values, rather than the default XYZ and
L*a*b*<br>
@@ -1327,6 +1682,13 @@ none,
supports it. See <a href="instruments.html">Operation of particular
instruments</a> for more details.<br>
<br>
+ <a name="R"></a><font size="-1">The <b>-R <i>fname.sp</i></b>
+ option allows specifying a reference spectrum</font> to preset the
+ reference values used to calculate delta E etc. This can be useful
+ in checking against a previously saved value (<b>'s' </b>command),
+ or in checking the instruments consistency against it's <a
+ href="#YW">reflective white reference spectrum</a>.<br>
+ <br>
<a name="X1"></a> The -<span style="font-weight: bold;">X <span
style="font-style: italic;">file.ccmx</span></span> option reads
a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
@@ -1343,10 +1705,8 @@ none,
colorimeters that rely on sensor spectral sensitivity calibration
information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
- Spyder5</span>).This
- can
- improve
- a colorimeters accuracy for a particular type of display.<br>
+ Spyder5</span>).This can improve a colorimeters accuracy for a
+ particular type of display.<br>
<br>
<a name="Yrn"></a> The -<span style="font-weight: bold;">Y r </span>and
@@ -1367,6 +1727,15 @@ none,
+
+
+
+
+
+
+
+
+
<b>-Y n</b> options overrides the refresh display mode set by the <a
href="#y">-y display type selection</a>, with <b>-Y</b><span
style="font-weight: bold;"> r</span> forcing refresh display mode,
@@ -1397,6 +1766,39 @@ none,
sets Xon/Xoff handshaking. This commend may be useful in workaround
serial communications issues with some systems and cables. <br>
<br>
+ <a name="YW"></a>The <b>-Y W:<i>fname.s</i>p</b> option allows
+ saving an instruments reference white tile reflectance spectrum to a
+ file. Reflective instruments use a white reference tile to calibrate
+ against, and typically the spectral reflectance of the white tile is
+ recorded inside the instrument to calibrate to. The saved spectrum
+ can be used to compare against the measurements of a reference grade
+ measurement of the white tile to check for tile deterioration, or
+ can be used as a reference for checking on instrument calibration
+ accuracy or consistency (See the <a href="#R">-R option</a>). Not
+ all instruments support this option (Currently the Spectrolino,
+ i1Pro, i1Pro2 and ColorMunki spectrometer.)<br>
+ <br>
+ <a name="YL"></a> The <b>-Y l|L</b> option is a special function
+ for X-Rite <a href="instruments.html#i1p2">i1Pro</a> instruments.
+ These instruments use an incandescent lamp as a light source for
+ reflectance measurement, and some instruments after some patterns of
+ use, can suffer from Lamp output thermal drift, due to the build up
+ of filament tungsten on the bulb inner surface. This function first
+ measures the Lamp drift, and then if the <b>-Y L</b> version is
+ used and the drift is greater than normal (0.06 - 0.1 Delta E), it
+ will attempt to remediate the problem by turning the lamp on for
+ some seconds so that it reaches normal operating temperature and is
+ able to re-circulate the tungsten back onto the filament properly.
+ It will then wait for the lamp to cool, and re-measure the drift.
+ These operations can take a few minutes, and it is advisable to let
+ the instrument cool off further after this operation, for 2 - 5
+ minutes, to allow it to return to normal operation conditions.<br>
+ <br>
+ The remediation function should be used infrequently or if the
+ repeatability of the instrument seems to be poorer than usual, as
+ frequent use may consume lamp life unnecessarily. If the lamp is
+ nearing its end of life, this function may not be effecive.<br>
+ <br>
<a name="D"></a>The <b>-D</b> flag causes communications and other
instrument diagnostics to be printed to stdout. A level can be set
between 1 .. 9, that may give progressively more verbose
diff --git a/doc/synthcal.html b/doc/synthcal.html
index 89f3fed..229f506 100644
--- a/doc/synthcal.html
+++ b/doc/synthcal.html
@@ -1,108 +1,138 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
-<head>
- <title>synthcal</title>
- <meta http-equiv="content-type"
- content="text/html; charset=ISO-8859-1">
- <meta name="author" content="Graeme Gill">
-</head>
-<body>
-<h2><b>spectro/synthcal</b></h2>
-<h3>Summary</h3>
-Create synthetic calibration file. The default is a linear calibration
-file.<br>
-<h3>Usage</h3>
-<font size="-1"><span style="font-family: monospace;">synthcal</span><i
- style="font-family: monospace;"> </i><span
- style="font-family: monospace;">[-options] </span><i
- style="font-family: monospace;">basename<br>
-&nbsp;-t
-N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i =
-input, o = output, d = display (default)<br>
-&nbsp;-d col_comb&nbsp;&nbsp;&nbsp;&nbsp; choose colorant combination
-from the following:<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ <head>
+ <title>synthcal</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/synthcal</b></h2>
+ <h3>Summary</h3>
+ Create synthetic calibration file. The default is a linear
+ calibration
+ file.<br>
+ <h3>Usage</h3>
+ <font size="-1"><span style="font-family: monospace;">synthcal</span><i
+ style="font-family: monospace;"> </i><span style="font-family:
+ monospace;">[-options] </span><i style="font-family:
+ monospace;">basename<br>
+ </i><span style="font-family: monospace;">&nbsp;-r
+ res&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set
+ the calibration resolution (default 256)<br>
+ &nbsp;-t
+ N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ i =
+ input, o = output, d = display (default)<br>
+ &nbsp;-d col_comb&nbsp;&nbsp;&nbsp;&nbsp; choose colorant
+ combination
+ from the following:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0:
-Print grey<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Print
+ grey<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
1:
-Video grey<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Video
+ grey<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
2:
-Print RGB<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Print
+ RGB<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
3:
-Video RGB<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-4:
-CMYK<br>
+Video
+ RGB<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-5:
-CMY<br>
+ 4:
+ CMYK<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 5:
+ CMY<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
6:
-CMYK + Light CM<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+CMYK
+ + Light CM<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
7:
-CMYK + Light CMK<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+CMYK
+ + Light CMK<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
8:
-CMYK + Red + Blue<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+CMYK
+ + Red + Blue<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
9:
-CMYK + Orange + Green<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+CMYK
+ + Orange + Green<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
10:
-CMYK + Light CMK + Light Light K<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+CMYK
+ + Light CMK + Light Light K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
11:
-CMYK + Orange + Green + Light CM<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+CMYK
+ + Orange + Green + Light CM<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
12:
-CMYK + Light CM + Medium CM<br>
-&nbsp;-D colorant&nbsp;&nbsp;&nbsp;&nbsp; Add or delete colorant from
-combination:<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+CMYK
+ + Light CM + Medium CM<br>
+ &nbsp;-D colorant&nbsp;&nbsp;&nbsp;&nbsp; Add or delete colorant
+ from
+ combination:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(Use
--?? to list known colorants)<br>
-</i></font><font size="-1"><i style="font-family: monospace;">&nbsp;-o
-o1,o2,o3,&nbsp;&nbsp;&nbsp; Set non-linear curve offset
-(default 0.0)</i></font><br>
-<font size="-1"><i style="font-family: monospace;">&nbsp;-s
-s1,s2,s3,&nbsp;&nbsp;&nbsp; Set non-linear curve scale
-(default 1.0)<br>
-&nbsp;-p p1,p2,p3,&nbsp;&nbsp;&nbsp; Set non-linear curve powers
-(default 1.0)<br>
-&nbsp;outfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Base name
-for output .cal file</i></font><br>
-<h3>Comments<br>
-</h3>
-This is the tool creates a calibration (<a href="File_Formats.html#.cal">.cal</a>)
-file that has a linear table
-for each channel. This is useful in setting up a display for
-evaluation, disabling printer calibration, testing, or to recover a
-display that has a strange set of
-Video LUTs loaded.<br>
-<br>
-<a name="t"></a>The <span style="font-weight: bold;">-t</span> option
-selects the type of device the calibration file is intended for.
-Default is display.<br>
-<br>
-<a name="d"></a>The <span style="font-weight: bold;">-d</span> option
-selects the device colorspace. The default for input and display is <font
- style="font-weight: bold;" size="-1"><span
- style="font-family: monospace;">Video RGB</span></font><font size="-1"><span
- style="font-family: monospace;">, while the default for output is <span
- style="font-weight: bold;">CMYK</span>.<br>
-</span></font><br>
-<a name="D"></a> The <b>-D</b> parameter modifies the colorspace set
-by <span style="font-weight: bold;">-d</span> by allowing individual
-colorants to be added or subtracted from the colorspace.<br>
-<br>
-Optionally it can be used to create a non-linear calibration file,
-useful for diagnostics. Each of the device channel curves can be
-given a gamma (power curve) shape, scaled to a maximum other than
-1.0, and offset from a value other than 0.0.<br>
-<br>
-</body>
+-??
+ to list known colorants)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;-o
+ o1,o2,o3,&nbsp;&nbsp;&nbsp; Set non-linear curve offset
+ (default 0.0)</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;-s
+ s1,s2,s3,&nbsp;&nbsp;&nbsp; Set non-linear curve scale
+ (default 1.0)<br>
+ &nbsp;-p p1,p2,p3,&nbsp;&nbsp;&nbsp; Set non-linear curve powers
+ (default 1.0)<br>
+ &nbsp;outfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Base name
+ for output .cal file</span></font><br>
+ <h3>Comments<br>
+ </h3>
+ This is the tool creates a calibration (<a
+ href="File_Formats.html#.cal">.cal</a>)
+ file that has a linear table
+ for each channel. This is useful in setting up a display for
+ evaluation, disabling printer calibration, testing, or to recover a
+ display that has a strange set of
+ Video LUTs loaded.<br>
+ <br>
+ <a name="r"></a>The <span style="font-weight: bold;">-r</span>
+ parameter
+ selects the table resolution. The default is 256.<br>
+ <br>
+ <a name="t"></a>The <span style="font-weight: bold;">-t</span>
+ option
+ selects the type of device the calibration file is intended for.
+ Default is display.<br>
+ <br>
+ <a name="d"></a>The <span style="font-weight: bold;">-d</span>
+ option
+ selects the device colorspace. The default for input and display is
+ <font style="font-weight: bold;" size="-1"><span style="font-family:
+ monospace;">Video RGB</span></font><font size="-1"><span
+ style="font-family: monospace;">, while the default for output
+ is <span style="font-weight: bold;">CMYK</span>.<br>
+ </span></font><br>
+ <a name="D"></a> The <b>-D</b> parameter modifies the colorspace
+ set
+ by <span style="font-weight: bold;">-d</span> by allowing
+ individual
+ colorants to be added or subtracted from the colorspace.<br>
+ <br>
+ Optionally it can be used to create a non-linear calibration file,
+ useful for diagnostics. Each of the device channel curves can be
+ given a gamma (power curve) shape, scaled to a maximum other than
+ 1.0, and offset from a value other than 0.0.<br>
+ <br>
+ </body>
</html>
diff --git a/doc/targen.html b/doc/targen.html
index 81b331b..ef84f81 100644
--- a/doc/targen.html
+++ b/doc/targen.html
@@ -12,8 +12,10 @@
Generate a profiling test target values&nbsp;<a
href="File_Formats.html#.ti1">.ti1</a> file. &nbsp;<b>targen</b>
is used to generate the device channel test point values for
- grayscale, RGB, CMY, CMYK or N-color output or display
- devices.&nbsp;
+ grayscale, RGB, CMY, CMYK or N-color output or display devices. <br>
+ <br>
+ [ Note though that colprof will only create RGB, CMY or CMYK
+ profiles. ]<br>
<h3>Usage Summary</h3>
<small><span style="font-family: monospace;">targen [options]
outfile</span><br style="font-family: monospace;">
@@ -43,6 +45,8 @@
+
+
0: Print grey</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -60,6 +64,8 @@
+
+
&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; 1: Video grey</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -78,6 +84,8 @@
+
+
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Print RGB</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
@@ -103,6 +111,8 @@
+
+
5: CMY<br style="font-family: monospace;">
</span><span style="font-family: monospace;">&nbsp;&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;
@@ -125,6 +135,8 @@
+
+
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7:
CMYK + Light CMK</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -151,6 +163,8 @@ Red
+
+
+ Blue</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;
@@ -182,6 +196,8 @@ Red
+
+
&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 12:
CMYK + Light CM + Medium CM</span><br style="font-family:
monospace;">
@@ -206,6 +222,8 @@ Red
+
+
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0: Additive</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
@@ -236,6 +254,8 @@ Red
+
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4: Black</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -254,6 +274,8 @@ Red
+
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5:
Orange</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -273,6 +295,8 @@ Red
+
+
6: Red</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -291,6 +315,8 @@ Red
+
+
7: Green</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -309,6 +335,8 @@ Red
+
+
8: Blue</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -327,6 +355,8 @@ Red
+
+
9: White</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -345,6 +375,8 @@ Red
+
+
10: Light Cyan</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -363,6 +395,8 @@ Red
+
+
11: Light Magenta</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -381,6 +415,8 @@ Red
+
+
12: Light Yellow</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -398,6 +434,8 @@ Red
+
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp; 13: Light Black</span><br style="font-family:
monospace;">
@@ -418,6 +456,8 @@ Red
+
+
14: Medium Cyan</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -436,6 +476,8 @@ Red
+
+
15: Medium Magenta</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -454,6 +496,8 @@ Red
+
+
16: Medium Yellow</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -471,6 +515,8 @@ Red
+
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; 17:
Medium Black</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -489,6 +535,8 @@ Red
+
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 18: Light
Light Black<br>
&nbsp;<a href="#G">-G</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -507,6 +555,8 @@ Red
+
+
Generate good optimzed points rather than Fast<br
style="font-family: monospace;">
</span><span style="font-family: monospace;">&nbsp;</span><a
@@ -534,6 +584,8 @@ Red
+
+
steps</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -550,6 +602,8 @@ Red
+
+
Single channel steps (default 0)</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -577,6 +631,8 @@ steps
+
+
0)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#m">-m steps</a><span
@@ -596,6 +652,8 @@ steps
+
+
Multidimensional device space cube steps (default 0)</span></small><br
style="font-family: monospace;">
<small><span style="font-family: monospace;"><small><span
@@ -616,6 +674,8 @@ steps
+
+
Multidimensional body centered cubic steps (default 0)<br>
</span></small></span>&nbsp; <span style="font-family:
monospace;"></span><a style="font-family: monospace;" href="#f">-f
@@ -633,6 +693,8 @@ steps
+
+
patches</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -649,6 +711,8 @@ steps
+
+
Add iterative &amp; adaptive full spread patches to total
(default 836)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -667,6 +731,8 @@ steps
+
+
Default is Optimised Farthest Point Sampling (OFPS)<br
style="font-family: monospace;">
</span><span style="font-family: monospace;">&nbsp; </span><a
@@ -694,6 +760,8 @@ for
+
+
full spread</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp; </span><a
style="font-family: monospace;" href="#r">-r</a><span
@@ -720,6 +788,8 @@ for
+
+
full spread</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp; </span><a
style="font-family: monospace;" href="#R">-R</a><span
@@ -746,6 +816,8 @@ for
+
+
full spread</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp; </span><a
style="font-family: monospace;" href="#q">-q</a><span
@@ -772,6 +844,8 @@ for
+
+
full spread<br>
</span></small><small><span style="font-family: monospace;">&nbsp;
</span><a style="font-family: monospace;" href="#Q">-Q</a><span
@@ -805,6 +879,8 @@ centered
+
+
cubic grid for full spread</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp; </span><a
@@ -832,6 +908,8 @@ centered
+
+
cubic grid for full spread</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp; </span><a
@@ -859,6 +937,8 @@ for
+
+
B.C.C. grid, default 0.333300</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp; </span><a
@@ -891,6 +971,8 @@ spread
+
+
(default iterative)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#l">-l ilimit</a><span
@@ -912,6 +994,8 @@ ink
+
+
limit in %(default = none, or estimated from profile)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#p">-p power</a><span
@@ -938,6 +1022,8 @@ device
+
+
values.</span></small><br style="font-family: monospace;">
<small><span style="font-family: monospace;"></span><span
style="font-family: monospace;">&nbsp;</span><a
@@ -967,12 +1053,20 @@ device
+
+
Filter out samples outside Lab sphere.<br>
&nbsp;<a href="#O">-O</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Don't re-order display RGB patches for minimum delay<br
- style="font-family: monospace;">
- </span> <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#w">-w</a><span
+
+
+ Don't re-order display RGB patches for minimum delay</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"><small><span
+ style="font-family: monospace;">&nbsp;<a href="#U">-U</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Don't filter out duplicate patches<br>
+ </span></small>&nbsp;</span><span style="font-family:
+ monospace;"></span><a style="font-family: monospace;" href="#w">-w</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -989,6 +1083,8 @@ device
+
+
Dump diagnostic outfile.x3d.html file (Lab locations)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#W">-W</a><span
@@ -1015,6 +1111,8 @@ device
+
+
Base name for output(.ti1)</span></small> <br>
<h3>Usage Details and Discussion<br>
</h3>
@@ -1091,6 +1189,8 @@ device
+
+
5</span> will generate steps at 0.0 0.25 0.5 0.75 and 1.0, while
the option <span style="font-weight: bold;">-s 5 -p 2.0</span> will
generate steps at 0.0 0.0625 0.25 0.5625 and 1.0. By default, no per
@@ -1153,6 +1253,8 @@ device
+
+
<b>-b</b> flags, is not to duplicate test values already created by
a previous type.<br>
<br>
@@ -1323,18 +1425,11 @@ device
accuracy of measuring and modelling the lighter regions, given a
fixed number of test points and profile quality/grid resolution. The
parameter will also be used in an analogous way to the <small><a
- href="targen.html#p">-p power</a>
- value in changing the distribution of </small><small><a
- href="targen.html#s">-s steps</a>, </small><small><a
- href="targen.html#g">-g steps</a>, </small><small><a
- href="targen.html#m">-m steps</a></small>
- and <small><small><a href="targen.html#b">-b
-
-
-
-
-
- steps</a></small></small> patches.<br>
+ href="targen.html#p">-p power</a> value in changing the
+ distribution of </small><small><a href="targen.html#s">-s steps</a>,
+ </small><small><a href="targen.html#g">-g steps</a>, </small><small><a
+ href="targen.html#m">-m steps</a></small> and <small><small><a
+ href="targen.html#b">-b steps</a></small></small> patches.<br>
<br>
<a name="F"></a> The <b>-F</b> flag and parameters is used to
define an L*a*b* sphere to filter the test points through. Only test
@@ -1359,12 +1454,15 @@ device
this re-ordering, leaving the patches in whatever order they were
generated.<br>
<br>
+ <a name="U"></a> The <b>-U</b> flag disables the normal filtering
+ out of duplicate patches.<br>
+ <br>
<a name="w"></a> The <b>-w</b> flag causes a diagnostic <a
- href="File_Formats.html#X3DOM">X3DOM</a> .x3d.html file to be created, in
- which the test points are plotted as small spheres in L*a*b*
- colorspace. Note that for a CMYK device, the point spacing may seem
- strange, since the extra K dimension is compressed into the 3
- dimensional L*a*b* space. <a name="W"></a>If the <span
+ href="File_Formats.html#X3DOM">X3DOM</a> .x3d.html file to be
+ created, in which the test points are plotted as small spheres in
+ L*a*b* colorspace. Note that for a CMYK device, the point spacing
+ may seem strange, since the extra K dimension is compressed into the
+ 3 dimensional L*a*b* space. <a name="W"></a>If the <span
style="font-weight: bold;">-W</span> flag is given, the plot will
be in device space, with only the first 3 dimensions of each point
being plotted.<br>
diff --git a/doc/ti3_format.html b/doc/ti3_format.html
index 559aa12..ca1be87 100644
--- a/doc/ti3_format.html
+++ b/doc/ti3_format.html
@@ -58,6 +58,7 @@
+
"<span style="font-weight: bold;">DISPLAY</span>",&nbsp; <span
style="font-weight: bold;">"INPUT"</span> or <span
style="font-weight: bold;">"EMISINPUT"</span>.<br>
@@ -75,6 +76,13 @@
what the valid device gamut is, and what total ink limit should be
used in creating the profile tables.<br>
<br>
+ An <span style="font-weight: bold;">"OUTPUT"</span> type device may
+ have an <span style="font-weight: bold;">ILLUMINANT_WHITE_POINT_XYZ</span>
+ keyword that contains the XYZ of the illuminant used to compute the
+ CIE values from spectral reflectance or transmittance values. If
+ this tag is absent, the illuminant is assumes to be ICC standard
+ D50.<br>
+ <br>
A <span style="font-weight: bold;">"DISPLAY"</span> type device may
have a <span style="font-weight: bold;">LUMINANCE_XYZ_CDM2</span>
keyword that contains the absolute XYZ value of white in candelas
@@ -83,6 +91,7 @@
+
119.657745 121.474236".<br>
<br>
</span>A display device may also have a <span style="font-weight:
@@ -174,12 +183,14 @@ Cyan
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
C<br>
&nbsp;&nbsp;&nbsp; Magenta &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; M<br>
@@ -189,6 +200,7 @@ Cyan
+
Y<br>
&nbsp;&nbsp;&nbsp; Black &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -196,6 +208,7 @@ Cyan
+
K<br>
&nbsp;&nbsp;&nbsp; Orange &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -203,6 +216,7 @@ Cyan
+
O<br>
&nbsp;&nbsp;&nbsp; Red
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -210,6 +224,7 @@ Cyan
+
R<br>
&nbsp;&nbsp;&nbsp; Green &nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -217,6 +232,7 @@ Cyan
+
G<br>
&nbsp;&nbsp;&nbsp; Blue &nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -224,6 +240,7 @@ Cyan
+
B<br>
&nbsp;&nbsp;&nbsp; White &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
@@ -234,6 +251,7 @@ Cyan
+
c<br>
&nbsp;&nbsp;&nbsp; Light
Magenta&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -241,6 +259,7 @@ Cyan
+
m<br>
&nbsp;&nbsp;&nbsp; Light
Yellow&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -248,6 +267,7 @@ Cyan
+
y<br>
&nbsp;&nbsp;&nbsp; Light
Black&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -255,6 +275,7 @@ Cyan
+
k<br>
&nbsp;&nbsp;&nbsp; Medium Cyan&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2c<br>
diff --git a/doc/tiffgamut.html b/doc/tiffgamut.html
index 9534717..fc60c31 100644
--- a/doc/tiffgamut.html
+++ b/doc/tiffgamut.html
@@ -35,8 +35,8 @@
href="Scenarios.html#LP3">Image dependent gamut mapping using
device links</a> for an example workflow.<br>
<br>
- See <a href="3dformat.html">3D Viewing
- Format</a> for switching to VRML or X3D output format.<br>
+ See <a href="3dformat.html">3D Viewing Format</a> for switching to
+ VRML or X3D output format.<br>
<h3>Usage Summary</h3>
<small><span style="font-family: monospace;">tiffgamut [-v level]
[profile.icm | embedded.tif/jpg] infile1.tif/jpg
@@ -47,6 +47,7 @@
+
Verbose</span><br style="font-family: monospace;">
&nbsp; <span style="font-family: monospace;">-d
sres&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Surface resolution
@@ -58,6 +59,7 @@ emit
+
X3DOM .x3d.html file as well as CGATS .gam file</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -67,6 +69,7 @@ Don't
+
add X3DOM axes or white/black point</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-k&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -76,6 +79,7 @@ Add
+
markers for prim. &amp; sec. "cusp" points<br>
&nbsp;-f perc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Filter by
popularity, perc = percent to use<br style="font-family:
@@ -90,6 +94,7 @@ s
+
= saturation, a = absolute (default), d = profile default</span></small><small><span
style="font-family: monospace;"></span></small><br
style="font-family: monospace;">
@@ -105,6 +110,7 @@ r
+
= reverse (priority: monochrome &gt; matrix &gt; lut)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><span
style="font-family: monospace;">-p oride</span><span
@@ -124,6 +130,7 @@ either
+
an enumerated choice, or a parameter:value change</span><span
style="font-family: monospace;"></span><br style="font-family:
monospace;">
@@ -138,6 +145,7 @@ either
+
pe - Print evaluation environment (CIE 116-1995)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;
@@ -146,6 +154,7 @@ either
+
pc - Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
style="font-family: monospace;"></span><span style="font-family:
monospace;"></span><br style="font-family: monospace;">
@@ -159,6 +168,7 @@ either
+
&nbsp; mb - Monitor in bright work environment</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
@@ -186,6 +196,7 @@ s:surround&nbsp;&nbsp;
+
n = auto, a = average, m = dim, d = dark,</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -195,6 +206,7 @@ s:surround&nbsp;&nbsp;
+
&nbsp; &nbsp;&nbsp; c = transparency (default average)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -204,6 +216,7 @@ w:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Adapted white point as XYZ (default media white)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -213,6 +226,7 @@ w:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Adapted white point as x, y</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -222,6 +236,7 @@ a:adaptation
+
Adaptation luminance in cd.m^2 (default 50.0)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -231,6 +246,7 @@ b:background
+
Background % of image luminance (default 20)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; l:imagewhite Image
white in cd.m^2 if surround = auto (default 250)</span></small><br
@@ -243,6 +259,7 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
Flare light % of image luminance (default 1)<br>
</span></small>&nbsp;</span><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -257,8 +274,13 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
g:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare color as
- x, y<br>
+ x, y</span></small><br>
+ <small><span style="font-family: monospace;"><small><span
+ style="font-family: monospace;">&nbsp;-x
+ pcent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Expand/compress gamut
+ cylindrically by percent</span></small><br>
&nbsp;-O outputfile Override the default output filename &amp;
extension.<br style="font-family: monospace;">
</span></small><br>
@@ -340,6 +362,12 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
viewing environment, or controlling particular viewing condition
parameters. This is only functional if an ICC profile is provided.<br>
<br>
+ The <b>-x</b> parameter allows expanding or compressing the
+ resulting gamut in a cylindrical direction by the given percentage
+ :- i.e "-x 120" will expand by 20%. This may be useful for creating
+ a general compression gamut mapping by using such an expanded device
+ gamut as input to <a href="collink.html#g">collink -g or -G</a>.<br>
+ <br>
The <span style="font-weight: bold;">-O</span> parameter allows the
output file name &amp; extension to be specified independently of
the last tiff/jpeg filename. Note that the full filename must be
diff --git a/doc/txt2ti3.html b/doc/txt2ti3.html
index 0fc467d..783d3b6 100644
--- a/doc/txt2ti3.html
+++ b/doc/txt2ti3.html
@@ -28,12 +28,17 @@
-d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Set
+
type of device as Display, not Output<br>
-i&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Set
- type of device as Input, not Output<br style="font-family:
- monospace;">
+
+ type of device as Input, not Output</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;">-T
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Transpose sample name Letters and Numbers<br>
</span></small><small><span style="font-family: monospace;"></span><i
style="font-family: monospace;">[devfile]</i><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; Input
@@ -44,6 +49,7 @@ Set
Input
CIE,
+
Spectral or Device &amp; Spectral file (typically file.txt)</span><br
style="font-family: monospace;">
<i style="font-family: monospace;">[specfile]</i><span
@@ -97,6 +103,11 @@ CIE,
appropriate range is, in order to scale to Argyll's standard range 0
.. 100.0.<br>
<br>
+ If the -T flag is used, then the patch location will be transposed
+ from letter/number to letter/numer - i.e.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; B5 -&gt; E2 <br>
+ <br>
<br>
</body>
</html>
diff --git a/doc/xicclu.html b/doc/xicclu.html
index 831977d..bd98058 100644
--- a/doc/xicclu.html
+++ b/doc/xicclu.html
@@ -3,7 +3,7 @@
<head>
<title>xicclu</title>
<meta http-equiv="content-type" content="text/html;
- charset=ISO-8859-1">
+ charset=windows-1252">
<meta name="author" content="Graeme Gill">
</head>
<body>
@@ -29,9 +29,9 @@
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#v">-v level</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Verbosity level 0 - 2 (default = 1)</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
+ Verbosity level 0 - 2 (default = 1)<br style="font-family:
+ monospace;">
+ </span> <span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#g">-g</a><span
style="font-family: monospace;"> &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; Plot slice instead of looking colors up. (Default
@@ -39,8 +39,11 @@
&nbsp;<a href="#Gs">-G s:L:a:b</a>&nbsp;&nbsp;&nbsp;&nbsp;
Override plot slice start with Lab or Jab co-ordinate<br>
&nbsp;<a href="#Ge">-G e:L:a:b</a>&nbsp;&nbsp;&nbsp;&nbsp;
- Override plot slice end with Lab or Jab co-ordinate<br
- style="font-family: monospace;">
+ Override plot slice end with Lab or Jab co-ordinate<br>
+ &nbsp;<a href="#V">-V</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Use 'vcgt' calibration tag from profile<br style="font-family:
+ monospace;">
</span><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#f">-f function</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp; f = forward,
@@ -54,6 +57,8 @@ if
+
+
inverted forward, ib = inverted backwards</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -67,10 +72,13 @@ if
+
+
</span></small><small><span style="font-family: monospace;"> p =
perceptual, </span></small><small><span style="font-family:
- monospace;">s = saturation</span><span style="font-family:
- monospace;"></span><br style="font-family: monospace;">
+ monospace;">s = saturation, A = disp. abs. measurements</span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#o">-o order</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -79,6 +87,8 @@ if
+
+
n = normal (priority: lut &gt; matrix &gt; monochrome)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -89,6 +99,8 @@ r
+
+
reverse (priority: monochrome &gt; matrix &gt; lut)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -99,6 +111,8 @@ r
+
+
x = XYZ_PCS, X = XYZ * 100, l = Lab_PCS, L = LCh, y = Yxy,<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j =
CIECAM02 Appearance Jab, J = CIECAM02 Appearance JCh<br>
@@ -111,16 +125,22 @@ Scale
+
+
device range 0.0 - scale rather than 0.0 - 1.0<br>
</span></small><br>
&nbsp; <small><span style="font-family: monospace;"><small><span
style="font-family: monospace;"><a href="#e">-e flag</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
Video encode device input as:<br>
&nbsp;<a href="#E">-E flag</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
Video decode device output as:<br>
&nbsp;&nbsp;&nbsp;&nbsp;
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -159,6 +179,8 @@ h
+
+
= 0.5 K, x = max K, r = ramp K (def.)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -169,6 +191,8 @@ l
+
+
= extra PCS input is portion of K locus</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -179,6 +203,8 @@ v
+
+
= extra PCS input is K target value</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -192,6 +218,8 @@ stle:
+
+
K level at White 0.0 - 1.0</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -202,6 +230,8 @@ stpo:
+
+
start point of transition Wh 0.0 - Bk 1.0</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -212,6 +242,8 @@ enpo:
+
+
End point of transition Wh 0.0 - Bk 1.0</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -222,6 +254,8 @@ enle:
+
+
K level at Black 0.0 - 1.0</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -232,6 +266,8 @@ shape:
+
+
1.0 = straight, 0.0-1.0 concave, 1.0-2.0 convex</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -246,6 +282,8 @@ extra
+
+
PCS input to dual curve limits</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -273,6 +311,8 @@ actual
+
+
target values if clipped<br>
&nbsp;<a href="#b">-b</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
use
@@ -282,6 +322,8 @@ CAM
+
+
Jab for clipping<br style="font-family: monospace;">
</span><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#m">-m</a><span
@@ -304,6 +346,8 @@ either
+
+
an enumerated choice, or a parameter:value change</span><span
style="font-family: monospace;"></span><br style="font-family:
monospace;">
@@ -319,6 +363,8 @@ pe
+
+
- Print evaluation environment (CIE 116-1995)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;
@@ -328,6 +374,8 @@ pc
+
+
- Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
style="font-family: monospace;"></span><span style="font-family:
monospace;"></span><br style="font-family: monospace;">
@@ -342,6 +390,8 @@ pc
+
+
mb - Monitor in bright work environment</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
@@ -372,6 +422,8 @@ n
+
+
= auto, a = average, m = dim, d = dark,</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -382,6 +434,8 @@ n
+
+
&nbsp;&nbsp;&nbsp; c = transparency (default average)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -392,6 +446,8 @@ Adapted
+
+
white point as XYZ (default media white, Abs: D50)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -402,6 +458,8 @@ Adapted
+
+
white point as x, y</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
a:adaptation
@@ -411,6 +469,8 @@ Adaptation
+
+
luminance in cd.m^2 (default 50.0)</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp; &nbsp;
@@ -428,12 +488,16 @@ light
+
+
% of image luminance (default 1)<br>
</span></small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
g:glare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare light % of ambient
(default 2)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
@@ -445,6 +509,8 @@ light
+
+
g:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FGare color as
x, y</span><br style="font-family: monospace;">
<br style="font-family: monospace;">
@@ -497,6 +563,8 @@ light
If a CAL file is used, then <b>-g</b> will simply plot the each
channels calibration curve. It will also plot the invers curve for <b>-f
+
+
b</b>.<br>
<br>
<a name="Gs"></a>The <span style="font-weight: bold;">-G </span><small><span
@@ -517,6 +585,11 @@ light
separated by the '<span style="font-weight: bold;">:'</span>
character (no spaces).<br>
<br>
+ <a name="V"></a>The <b>-V</b> flag tells xicclu to load the given
+ ICC profile, and the extract the 'vcgt' display calibration curves
+ from the profile. The calibration curves can then be looked up in
+ the normal way, or plotted using <b>-g.</b><br>
+ <br>
<a name="f"></a> The <b>-f</b> flag selects which type of table or
conversion is to be used. In addition to the usual four tables that
can be accessed in a fully populated Lut based profile, two
@@ -529,6 +602,9 @@ light
<a name="i"></a> The <b>-i</b> flag selects the intent table used
for a lut based profile. It also selects between relative and
absolute colorimetric for non-lut base profiles.<br>
+ The -A flag selects Display absolute measurement mode, where the
+ Luminance tag value is used restore absolute measurement XYZ values.
+ The PCS will be force to be XYZ with this selection.<br>
<br>
<a name="o"></a> A profile is allowed to contain more than the
minimum number of elements or table needed to describe a certain
@@ -566,9 +642,8 @@ light
between 0 and 255, use <span style="font-weight: bold;">-s 255.</span><br>
<br>
<a name="e"></a>The <b>-e</b> <i>flag</i> applies a Video encoding
- to the input. See <a
- href="collink.html#E"><b>-E</b></a> for
- the list of encodings.<br>
+ to the input. See <a href="collink.html#E"><b>-E</b></a> for the
+ list of encodings.<br>
<br>
<b><a name="E"></a></b>The <b>-E</b> <i>flag</i> applies a Video
encoding to the output. The possible encoding are:<br>
@@ -580,6 +655,8 @@ light
+
+
normal RGB 0..1 full range levels (default)<br>
&nbsp;&nbsp;&nbsp;&nbsp;
t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -587,6 +664,8 @@ light
+
+
RGB (16-235)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -594,6 +673,8 @@ light
+
+
Rec601 YCbCr SD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -601,6 +682,8 @@ light
+
+
Rec709 1125/60Hz YCbCr HD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -608,6 +691,8 @@ light
+
+
Rec709 1250/50Hz YCbCr HD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -615,6 +700,8 @@ light
+
+
Rec2020 YCbCr UHD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -622,6 +709,8 @@ light
+
+
Rec2020 Constant Luminance YCbCr UHD (16-235,240)/255 "TV"
levels<br>
</span></small></span></small><br>
@@ -635,6 +724,8 @@ light
+
+
with the addition of two extra options.<br>
<br>
&nbsp;Possible arguments to the <b>-k</b> option are:<br>
@@ -675,6 +766,8 @@ light
+
+
&nbsp; &nbsp;_______&nbsp; enle<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -684,6 +777,8 @@ light
+
+
&nbsp; &nbsp;/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;
@@ -693,6 +788,8 @@ light
+
+
&nbsp; /<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -702,6 +799,8 @@ light
+
+
&nbsp;/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -711,6 +810,8 @@ light
+
+
/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
stle&nbsp; | ------/<br>
@@ -726,6 +827,8 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
+
+
Black<br>
</tt><br>
<b><a name="kq"></a>-k q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2
diff --git a/gamut/gammap.c b/gamut/gammap.c
index e276b99..03b9502 100644
--- a/gamut/gammap.c
+++ b/gamut/gammap.c
@@ -23,8 +23,12 @@
* There is a general expectation (especially in comparing products)
* that the profile colorimetric intent be not strictly minimum delta E,
* but that it correct neutral axis, luminence range and keep hue
- * proportionality. Ideally there should be an intent that matches
+ * proportionality (i.e. clip with constant Hue and Luminance).
+ * Ideally there should be an intent that matches
* this, that can be selected for the colorimetric table (or perhaps be default).
+ * !! Maybe even the normal perceptual gamut mapping should use a !!
+ * !! Hue and Luminance preserving clipping ? Should this be the default !!
+ * !! for all inverse lookups ?? !!
*
* It might be good to offer the black mapping method as an option (icx_BPmap),
* as well as offering different profile (xicc/xlut.c) black point options
@@ -37,7 +41,7 @@
* messing up the guide vector mappings. Even if this is fixed, the
* actual neutral aim point within nearsmooth is Jab 0,0, while
* the mapping in gammap is from the source neutral to the chosen
- * ??????
+ * ?????? (is this fixed to some degree ?)
*/
@@ -519,10 +523,12 @@ static void map_trans(void *cntx, double out[3], double in[3]);
/* Return NULL on error. */
gammap *new_gammap(
int verb, /* Verbose flag */
- gamut *sc_gam, /* Source colorspace gamut */
+ gamut *sc_gam, /* Source colorspace gamut (L gamut if sh_gam != NULL) */
gamut *isi_gam, /* Input source image gamut (NULL if none) */
gamut *d_gam, /* Destination colorspace gamut */
icxGMappingIntent *gmi, /* Gamut mapping specification */
+ gamut *sh_gam, /* If not NULL, then use sc_gam for the luminence */
+ /* mapping, and sh_gam for the hull mapping (i.e. general compression) */
int src_kbp, /* Use K only black point as src gamut black point */
int dst_kbp, /* Use K only black point as dst gamut black point */
int dst_cmymap, /* masks C = 1, M = 2, Y = 4 to force 100% cusp map */
@@ -533,8 +539,8 @@ gammap *new_gammap(
char *diagname /* If non-NULL, write a gamut mapping diagnostic WRL */
) {
gammap *s; /* This */
- gamut *si_gam = NULL; /* Source image gamut (intersected with sc_gam) */
- gamut *scl_gam; /* Source colorspace gamut with rotation and L mapping applied */
+ gamut *si_gam = NULL; /* Source image gamut (intersected with sc_gam), assm. NULL if sh_gam */
+ gamut *scl_gam = NULL; /* Source colorspace gamut with rotation and L mapping applied */
gamut *sil_gam; /* Source image gamut with rotation and L mapping applied */
double s_cs_wp[3]; /* Source colorspace white point */
@@ -1261,18 +1267,28 @@ glumknf = 1.0;
}
#endif
- if ((scl_gam = parttransgamut(s, sc_gam)) == NULL) {
- fprintf(stderr,"gamut map: parttransgamut failed\n");
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
- free(s);
- return NULL;
+ /* If we were provided with a distinct source gamut hull, i.e. because */
+ /* we are doing a general compression/expansion, and sh_gam is an expanded/compressed */
+ /* destination gamut, use it for creating the nearsmth vectors */
+ if (sh_gam != NULL) {
+ scl_gam = sh_gam;
+
+ /* Map the source colorspace gamut through the L mapping */
+ } else {
+ if ((scl_gam = parttransgamut(s, sc_gam)) == NULL) {
+ fprintf(stderr,"gamut map: parttransgamut failed\n");
+ if (si_gam != sc_gam)
+ si_gam->del(si_gam);
+ free(s);
+ return NULL;
+ }
}
if (sc_gam == si_gam)
sil_gam = scl_gam;
else {
+ /* Map the source image gamut through the L mapping */
if ((sil_gam = parttransgamut(s, si_gam)) == NULL) {
fprintf(stderr,"gamut map: parttransgamut failed\n");
if (si_gam != sc_gam)
@@ -1322,7 +1338,8 @@ typedef struct {
s->igrey->del(s->igrey);
if (sil_gam != scl_gam)
sil_gam->del(sil_gam);
- scl_gam->del(scl_gam);
+ if (scl_gam != sh_gam)
+ scl_gam->del(scl_gam);
if (si_gam != sc_gam)
si_gam->del(si_gam);
free(s);
@@ -1493,7 +1510,8 @@ typedef struct {
s->igrey->del(s->igrey);
if (sil_gam != scl_gam)
sil_gam->del(sil_gam);
- scl_gam->del(scl_gam);
+ if (scl_gam != sh_gam)
+ scl_gam->del(scl_gam);
if (si_gam != sc_gam)
si_gam->del(si_gam);
free(s);
@@ -1523,7 +1541,8 @@ typedef struct {
s->igrey->del(s->igrey);
if (sil_gam != scl_gam)
sil_gam->del(sil_gam);
- scl_gam->del(scl_gam);
+ if (scl_gam != sh_gam)
+ scl_gam->del(scl_gam);
if (si_gam != sc_gam)
si_gam->del(si_gam);
free(s);
@@ -2275,7 +2294,8 @@ typedef struct {
if (sil_gam != scl_gam)
sil_gam->del(sil_gam);
- scl_gam->del(scl_gam);
+ if (scl_gam != sh_gam)
+ scl_gam->del(scl_gam);
if (si_gam != sc_gam)
si_gam->del(si_gam);
diff --git a/gamut/gammap.h b/gamut/gammap.h
index 69207a4..247ff65 100644
--- a/gamut/gammap.h
+++ b/gamut/gammap.h
@@ -58,6 +58,8 @@ gammap *new_gammap(
gamut *s_gam, /* Source image gamut (NULL if none) */
gamut *d_gam, /* Destination colorspace gamut */
icxGMappingIntent *gmi, /* Gamut mapping specification */
+ gamut *sh_gam, /* If not NULL, then use sc_gam for the luminence */
+ /* mapping, and sh_gam for the hull mapping (i.e. general compression) */
int src_kbp, /* Use K only black point as src gamut black point */
int dst_kbp, /* Use K only black point as dst gamut black point */
int dst_cmymap, /* masks C = 1, M = 2, Y = 4 to force 100% cusp map */
diff --git a/gamut/gamut.c b/gamut/gamut.c
index 3fc1c97..14b45c7 100644
--- a/gamut/gamut.c
+++ b/gamut/gamut.c
@@ -175,6 +175,7 @@ static int compute_vector_isect(gamut *s, double *p1, double *p2, double *min, d
static int compute_vector_isectns(gamut *s, double *p1, double *p2, gispnt *lp, int ll);
static double log_scale(gamut *s, double ss);
static int intersect(gamut *s, gamut *s1, gamut *s2);
+static int exp_cyl(gamut *s, gamut *s1, double ratio);
static int nexpintersect(gamut *s, gamut *s1, gamut *s2);
static int expdstbysrcmdst(gamut *s, gamut *s1, gamut *s2, gamut *s3,
void (*cvect)(void *cntx, double *p2, double *p1), void *cntx);
@@ -561,7 +562,8 @@ gamut *new_gamut(
double sres, /* Resolution (in rect coord units) of surface triangles */
/* 0.0 = default */
int isJab, /* Flag indicating Jab space */
-int isRast /* Flag indicating Raster rather than colorspace */
+int isRast /* Flag indicating Raster rather than colorspace, */
+ /* so that we only do one pass rather than two of surface fitting. */
) {
gamut *s;
@@ -658,6 +660,7 @@ int isRast /* Flag indicating Raster rather than colorspace */
s->getvert = getvert;
s->volume = volume;
s->intersect = intersect;
+ s->exp_cyl = exp_cyl;
s->nexpintersect = nexpintersect;
s->expdstbysrcmdst = expdstbysrcmdst;
s->radial = radial;
@@ -1206,6 +1209,128 @@ static int intersect(gamut *s, gamut *sa, gamut *sb) {
return 0;
}
+
+/* ------------------------------------ */
+
+/* Initialise this gamut with the source gamut */
+/* expanded cylindrically around the nautral axis by */
+/* the given ratio. */
+/* (We assume that the this gamut is currently empty) */
+static int exp_cyl(gamut *s, gamut *sa, double ratio) {
+ int i, j, k;
+ double bp[3], wp[3];
+
+ if IS_LIST_EMPTY(sa->tris)
+ triangulate(sa);
+
+ s->sres = sa->sres;
+
+ s->isJab = sa->isJab;
+
+ s->isRast = sa->isRast;
+
+ if (s->isRast) {
+ s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
+ s->no2pass = 1; /* Only do one pass */
+ }
+
+ for (j = 0; j < 3; j++)
+ s->cent[j] = sa->cent[j];
+
+ /* Clear some flags */
+ s->cswbset = 0;
+ s->cswbset = 0;
+ s->dcuspixs = 0;
+
+ /* Copy white & black points */
+ if (sa->cswbset) {
+ for (j = 0; j < 3; j++) {
+ s->cs_wp[j] = sa->cs_wp[j];
+ s->cs_bp[j] = sa->cs_bp[j];
+ s->cs_kp[j] = sa->cs_kp[j];
+ }
+ s->cswbset = sa->cswbset;
+
+ icmCpy3(wp, s->cs_wp);
+ icmCpy3(bp, s->cs_bp);
+
+ } else {
+ wp[0] = 100.0, wp[1] = 0.0, wp[2] = 0.0;
+ bp[0] = 0.0, bp[1] = 0.0, bp[2] = 0.0;
+ }
+
+ /* Don't filter the points (gives a more accurate result) */
+ s->nofilter = 1;
+
+ /* For each vertex */
+ for (i = 0; i < sa->nv; i++) {
+ double pp[3], cp[3];
+ double vv;
+
+ if (!(sa->verts[i]->f & GVERT_TRI))
+ continue;
+
+ icmCpy3(pp, sa->verts[i]->p); /* Point in question */
+
+ /* Parameter along neutral axis black to white */
+ vv = (pp[0] - bp[0])/(wp[0] - bp[0]);
+
+ /* lv is point at same L on neutral axis */
+ cp[0] = pp[0];
+ cp[1] = vv * (wp[1] - bp[1]) + bp[1];
+ cp[2] = vv * (wp[2] - bp[2]) + bp[2];
+
+ /* Convert to vector from neutral axis point */
+ icmSub3(pp, pp, cp);
+
+ /* Scale a,b */
+ pp[1] *= ratio;
+ pp[2] *= ratio;
+
+ /* Convert back to point */
+ icmAdd3(pp, pp, cp);
+
+ expand_gamut(s, pp);
+ }
+
+ /* Copy and expand cusps */
+ if (sa->cu_inited != 0) {
+ /* For each cusp */
+ for (i = 0; i < 6; i++) {
+ double pp[3], cp[3];
+ double vv;
+
+ icmCpy3(pp, sa->cusps[i]);
+
+ /* Parameter along neutral axis black to white */
+ vv = (pp[0] - bp[0])/(wp[0] - bp[0]);
+
+ /* lv is point at same L on neutral axis */
+ cp[0] = pp[0];
+ cp[1] = vv * (wp[1] - bp[1]) + bp[1];
+ cp[2] = vv * (wp[2] - bp[2]) + bp[2];
+
+ /* Convert to vector from neutral axis point */
+ icmSub3(pp, pp, cp);
+
+ /* Scale a,b */
+ pp[1] *= ratio;
+ pp[2] *= ratio;
+
+ /* Convert back to point */
+ icmAdd3(pp, pp, cp);
+
+ icmCpy3(s->cusps[i], pp);
+ }
+ s->cu_inited = sa->cu_inited;
+ }
+
+ s->nofilter = 0;
+
+ return 0;
+}
+
+
/* ------------------------------------ */
/* Initialise this gamut with neutral axis points from sa, */
@@ -4534,8 +4659,10 @@ double *gakp
}
//printf("~1 colorspace white %f %f %f, black %f %f %f, kblack %f %f %f\n", s->cs_wp[0], s->cs_wp[1], s->cs_wp[2], s->cs_bp[0], s->cs_bp[1], s->cs_bp[2], s->cs_kp[0],s->cs_kp[1],s->cs_kp[2]);
- if (gawp != NULL || gabp != NULL) {
+ if (gawp != NULL || gabp != NULL || gakp != NULL) {
//printf("~1 computing gamut white & black\n");
+ if (s->nv == 0)
+ return 1;
compgawb(s); /* make sure we have gamut white/black available */
}
diff --git a/gamut/gamut.h b/gamut/gamut.h
index e70d898..e74f942 100644
--- a/gamut/gamut.h
+++ b/gamut/gamut.h
@@ -249,7 +249,7 @@ struct _gamut {
double xvra; /* Extra vertex ratio - set/used by nssverts() */
int ssnverts; /* total ss verticies - set/used by nssverts() */
int ssvertn; /* Number of verts created for current triangle */
- sobol *ss; /* Sibol ss generator currently being used */
+ sobol *ss; /* Sobol ss generator currently being used */
gtri *nexttri; /* Context for getnexttri() */
@@ -315,14 +315,22 @@ struct _gamut {
/* Initialise this gamut with the intersection of the */
/* the two given gamuts. */
+ int (*exp_cyl)(struct _gamut *s, struct _gamut *s1, double ratio);
+ /* Initialise this gamut with the source gamut */
+ /* expanded cylindrically around the nautral axis by */
+ /* the given ratio. */
+
int (*nexpintersect)(struct _gamut *s, struct _gamut *s1, struct _gamut *s2);
- /* Return s1 expanded with neutral axis points */
- /* and then intersected with s2. */
+ /* Initialise this gamut with neutral axis points from sa, */
+ /* and then intersected with sb. */
int (*expdstbysrcmdst)(struct _gamut *s,
struct _gamut *dst, struct _gamut *sc, struct _gamut *dc,
void (*cvect)(void *cntx, double *p2, double *p1), void *cntx);
/* Expand dst by ((dc - sc) > 0) */
+ /* Initialise this gamut with the image/destination gamut sc */
+ /* expanded by the amount that dest (dc) colorspace is outside */
+ /* the source colorspace gamut. */
double (*radial)(struct _gamut *s, double out[3], double in[3]);
/* return point on surface in same radial direction. */
diff --git a/gamut/maptest.c b/gamut/maptest.c
index 433e719..ae74a1c 100644
--- a/gamut/maptest.c
+++ b/gamut/maptest.c
@@ -33,7 +33,6 @@
#include "rspl.h"
#include "gammap.h"
#include "vrml.h"
-#include "ui.h"
void usage(void) {
fprintf(stderr,"Map bteween two gamuts, Version %s\n",ARGYLL_VERSION_STR);
@@ -203,6 +202,7 @@ main(int argc, char *argv[]) {
gimg, /* Image gamut */
gout, /* Destination gamut */
&gmi,
+ NULL, /* No gamut hull gamut */
0, 0, /* Normal black points */
0, /* Normal CMY cusp mapping */
0, /* No relative weighting override */
diff --git a/gamut/smthtest.c b/gamut/smthtest.c
index b794ed0..71ba1e2 100644
--- a/gamut/smthtest.c
+++ b/gamut/smthtest.c
@@ -36,7 +36,6 @@
#include "gamut.h"
#include "nearsmth.h"
#include "vrml.h"
-#include "ui.h"
double m21po[3] = { 2.0, 1.0, 2.0 }; /* Many to 1 filter mixing power LCh (theoretically 2) */
diff --git a/h/aconfig.h b/h/aconfig.h
index 50275ea..f59d8a1 100644
--- a/h/aconfig.h
+++ b/h/aconfig.h
@@ -4,13 +4,32 @@
/* General project wide configuration */
+/*
+ * Author: Graeme W. Gill
+ *
+ * Copyright 2006 - 2016, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Version of Argyll release */
/* Bug fix = 4 bits */
/* minor number = 8 bits */
/* major number = 8 bits */
-#define ARGYLL_VERSION 0x01083
-#define ARGYLL_VERSION_STR "1.8.3"
+#ifndef USE_NG_VERSION
+# define ARGYLL_VERSION 0x01091
+# define ARGYLL_VERSION_STR "1.9.1"
+#else
+# define ARGYLL_VERSION NG_VERSION
+# define ARGYLL_VERSION_STR "NG_VERSION_STR"
+#endif
#if defined(NT)
# if defined(_WIN64)
@@ -21,13 +40,13 @@
#endif
#if defined(UNIX)
# if defined(__APPLE__)
-# if defined(__LP64__)
+# if defined(__P64__)
# define ARGYLL_BUILD_STR "OS X 64 bit"
# else
# define ARGYLL_BUILD_STR "OS X 32 bit"
# endif
# else
-# if defined(__LP64__)
+# if defined(__P64__)
# define ARGYLL_BUILD_STR "Linux 64 bit"
# else
# define ARGYLL_BUILD_STR "Linux 32 bit"
@@ -38,15 +57,26 @@
/* Maximum file path length */
#define MAXNAMEL 1024
+/* Maximum number of entries to setup for calibration */
+#define MAX_CAL_ENT 16384
+
/* A simpler #define to remove __APPLE__ from non OS X code */
-#if defined(UNIX) && !defined(__APPLE__)
-# define UNIX_X11 /* Unix like using X11 */
-#else
-# undef UNIX_X11
+#if defined(UNIX)
+# if defined(__APPLE__)
+# define UNIX_APPLE
+# undef UNIX_X11
+# else
+# define UNIX_X11
+# undef UNIX_APPLE
+# endif
+#endif
+
+#ifdef UNIX_X11
+# define USE_UCMM /* Enable the Unix micro CMM */
#endif
-#if defined(UNIX) && !defined(__APPLE__)
-#define USE_UCMM /* Enable the Unix micro CMM */
+#ifdef __cplusplus
+ }
#endif
#endif /* __CONFIG_H__ */
diff --git a/h/copyright.h b/h/copyright.h
index 7dc880e..3d8c5f7 100644
--- a/h/copyright.h
+++ b/h/copyright.h
@@ -1,5 +1,12 @@
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Embed a copyright string */
static volatile char __copyright__[] = "Copyright 1995-2013 Graeme W. Gill";
+#ifdef __cplusplus
+ }
+#endif
diff --git a/h/counters.h b/h/counters.h
index 0fbb11a..391dbe1 100644
--- a/h/counters.h
+++ b/h/counters.h
@@ -15,12 +15,16 @@
#ifndef COUNTERS_H
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* ------------------------------------------------------- */
/* Macros for a multi-dimensional counter. */
/* Declare the counter name nn, maximum di mxdi, dimensions di, & count */
-#define DCOUNT(nn, mxdi, di, start, reset, endp1) \
- int nn[mxdi]; /* counter value */ \
+#define DCOUNT(nn, mxdi, di, start, reset, endp1) \
+ int nn[mxdi]; /* counter value */ \
int nn##_di = (di); /* Number of dimensions */ \
int nn##_stt = (start); /* start count value */ \
int nn##_rst = (reset); /* reset on carry value */ \
@@ -256,5 +260,9 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#ifdef __cplusplus
+ }
+#endif
+
#define COUNTERS_H
#endif /* COUNTERS_H */
diff --git a/h/llist.h b/h/llist.h
index 1af31bf..0edd06f 100644
--- a/h/llist.h
+++ b/h/llist.h
@@ -1,9 +1,13 @@
-/* A set of linked list utilities, implimented as macros. */
+/* A set of doubly linked list utilities, implimented as macros. */
/* Copyright 1995, 2000 Graeme W. Gill */
#ifndef _LLIST_H_
-/* A link list structure */
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* A doubly link list structure */
#define LINKSTRUCT(obj) \
struct { \
obj *fwd; /* Forward link */ \
@@ -87,6 +91,10 @@ struct { \
#define IS_ONE_ITEM(objp) \
((objp) == (objp)->_llistp.fwd)
+#ifdef __cplusplus
+ }
+#endif
+
#define _LLIST_H_
#endif /* _LLIST_H_ */
diff --git a/h/sort.h b/h/sort.h
index 98bee8f..8440425 100644
--- a/h/sort.h
+++ b/h/sort.h
@@ -1,4 +1,6 @@
+#ifndef SORT_H
+
/*
* Copyright 1996 - 2010 Graeme W. Gill
* All rights reserved.
@@ -7,13 +9,17 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/*
* Heapsort macro - sort smallest to largest.
* Heapsort is guaranteed nlogn, doesn't need any
* extra storage, but often isn't as fast as quicksort.
*/
-/* Need to #define HEAP_COMPARE(A,B) so it returns true if A < B */
+/* To sort ascenting, need to #define HEAP_COMPARE(A,B) so it returns true if A < B */
/* Note that A will be ARRAY[a], and B will be ARRAY[b] where a and b are indexes. */
/* TYPE should be the type of each entry of the ARRAY */
#define HEAPSORT(TYPE,ARRAY,NUMBER) \
@@ -60,3 +66,9 @@
} \
}
+#ifdef __cplusplus
+ }
+#endif
+
+#define SORT_H
+#endif /* SORT_H */
diff --git a/h/xlist.h b/h/xlist.h
index dc03019..a9b3c6f 100644
--- a/h/xlist.h
+++ b/h/xlist.h
@@ -3,6 +3,10 @@
#ifndef _XLIST_H_
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* An expanding list structure */
#define XLIST(objtype, name) \
struct { \
@@ -51,6 +55,10 @@ struct { \
#define XLIST_FREE(xlp) \
{ if ((xlp)->_no > 0) free((xlp)->list); }
+#ifdef __cplusplus
+ }
+#endif
+
#define _XLIST_H_
#endif /* _XLIST_H_ */
diff --git a/icc/License4.txt b/icc/License4.txt
new file mode 100644
index 0000000..61be41a
--- /dev/null
+++ b/icc/License4.txt
@@ -0,0 +1,22 @@
+*************************************************************************
+Copyright (c) 1997-2015 Graeme W. Gill
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*************************************************************************
diff --git a/icc/Readme.txt b/icc/Readme.txt
index d39e9da..2b5fd53 100644
--- a/icc/Readme.txt
+++ b/icc/Readme.txt
@@ -74,7 +74,7 @@ Package contents:
icclib.zip ZIP archive of the following files
README.txt This file.
- License.txt Important! - Permissions for use of this package.
+ License4.txt Important! - Permissions for use of this package.
icc.c Library source file.
iccstd.c Library source that uses stdio and malloc system calls.
diff --git a/icc/afiles b/icc/afiles
index acb730e..3ee789a 100644
--- a/icc/afiles
+++ b/icc/afiles
@@ -1,5 +1,5 @@
Readme.txt
-License.txt
+License4.txt
todo.txt
log.txt
Jamfile
diff --git a/icc/icc.c b/icc/icc.c
index d5b72ce..b239060 100644
--- a/icc/icc.c
+++ b/icc/icc.c
@@ -10,7 +10,7 @@
* Copyright 1997 - 2013 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/*
@@ -1034,7 +1034,7 @@ unsigned int str2tag(
}
/* helper - return 1 if the string doesn't have a */
-/* null terminator within len, return 0 has null at exactly len, */
+/* null terminator within len, return 0 if it has null at exactly len, */
/* and 2 if it has null before len. */
/* Note: will return 1 if len == 0 */
static int check_null_string(char *cp, int len) {
@@ -8241,18 +8241,19 @@ static int icmTextDescription_core_read(
p->size = read_UInt32Number(bp);
bp += 4;
if (p->size > 0) {
+ int chrv;
if (bp > end || p->size > (end - bp)) {
*bpp = bp;
sprintf(icp->err,"icmTextDescription_read: Data too short to read Ascii string");
return icp->errc = 1;
}
- if ((rv = check_null_string(bp,p->size)) == 1) {
+ if ((chrv = check_null_string(bp,p->size)) == 1) {
*bpp = bp;
sprintf(icp->err,"icmTextDescription_read: ascii string is not terminated");
return icp->errc = 1;
}
#ifdef ICM_STRICT
- if (rv == 2) {
+ if (chrv == 2) {
*bpp = bp;
sprintf(icp->err,"icmTextDescription_read: ascii string is shorter than count");
return icp->errc = 1;
@@ -8263,6 +8264,9 @@ static int icmTextDescription_core_read(
}
strcpy(p->desc, bp);
bp += p->size;
+
+ if (chrv == 2)
+ p->size = strlen(bp); /* Repair string */
}
/* Read the Unicode string */
@@ -8276,20 +8280,21 @@ static int icmTextDescription_core_read(
p->ucSize = read_UInt32Number(bp);
bp += 4;
if (p->ucSize > 0) {
- ORD16 *up;
+ int chrv;
+ ORD16 *up, len;
char *tbp;
if (bp > end || p->ucSize > (end - bp)/2) {
*bpp = bp;
sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
return icp->errc = 1;
}
- if ((rv = check_null_string16(bp,p->ucSize)) == 1) {
+ if ((chrv = check_null_string16(bp,p->ucSize)) == 1) {
*bpp = bp;
sprintf(icp->err,"icmTextDescription_read: Unicode string is not terminated");
return icp->errc = 1;
}
#ifdef ICM_STRICT
- if (rv == 2) {
+ if (chrv == 2) {
*bpp = bp;
sprintf(icp->err,"icmTextDescription_read: Unicode string is shorter than count");
return icp->errc = 1;
@@ -8298,10 +8303,12 @@ static int icmTextDescription_core_read(
if ((rv = p->allocate((icmBase *)p)) != 0) {
return rv;
}
- for (up = p->ucDesc, tbp = bp; tbp[0] != 0 || tbp[1] != 0; up++, tbp += 2)
+ for (len = 0, up = p->ucDesc, tbp = bp; tbp[0] != 0 || tbp[1] != 0; up++, tbp += 2, len++)
*up = read_UInt16Number(tbp);
*up = 0; /* Unicode null */
bp += p->ucSize * 2;
+ if (chrv == 2)
+ p->ucSize = len+1; /* Repair string */
}
/* Read the ScriptCode string */
@@ -8387,7 +8394,7 @@ static int icmTextDescription_write(
/* Core write the contents of the object. Return 0 on sucess, error code on failure */
static int icmTextDescription_core_write(
icmTextDescription *p,
- char **bpp /* Pointer to buffer pointer, returns next after read */
+ char **bpp /* Pointer to buffer pointer, returns next after write */
) {
icc *icp = p->icp;
char *bp = *bpp;
@@ -11728,18 +11735,20 @@ static int icc_read_x(
icmCpy3x3(p->iwpchtmx, icmWrongVonKries);
}
- p->useArts = 0; /* Don't save it if it wasn't in profile */
+ p->useArts = 0; /* Don't save it, as it wasn't in profile */
}
- p->autoWpchtmx = 0; /* It's been set on reading - don't set automatically */
+ p->wpchtmx_class = p->header->deviceClass; /* It's set for this class now */
}
- /* If this is a Display profile, check if there is a 'chad' tag, and read it */
- /* in if it exists. We will use this latter. */
+ /* If this is a Display or Output profile, check if there is a 'chad' tag, and read it */
+ /* in if it exists. We will use this latter when we interpret absolute colorimetric, */
+ /* and this also prevents auto creation of a chad tag on write if wrD/OChad is set. */
{
icmS15Fixed16Array *chadTag;
- if (p->header->deviceClass == icSigDisplayClass
+ if ((p->header->deviceClass == icSigDisplayClass
+ || p->header->deviceClass == icSigOutputClass)
&& (chadTag = (icmS15Fixed16Array *)p->read_tag(p, icSigChromaticAdaptationTag)) != NULL
&& chadTag->ttype == icSigS15Fixed16ArrayType
&& chadTag->size == 9) {
@@ -11754,12 +11763,18 @@ static int icc_read_x(
p->chadmx[2][1] = chadTag->data[7];
p->chadmx[2][2] = chadTag->data[8];
- p->chadValid = 1;
-
- p->useChad = 1; /* Use it when writing */
+ p->naturalChad = 1;
+ p->chadmxValid = 1;
}
}
+ /* It would be nice to have an option to convert 'chad' based profile */
+ /* into non-chad profiles, but this is non trivial, since the wpchtmx would */
+ /* need to be determined from the chad matrix. While this is technically */
+ /* possible (see chex.c for an attempt at this), it is not easy, and */
+ /* it's possible for the chad matrix to be a non Von Kries type transformation, */
+ /* which cannot be exactly decomposed into a cone space matrix + Von Kries scaling. */
+
return er;
}
@@ -11855,21 +11870,29 @@ static int icc_check_id(
return 2; /* Didn't match */
}
-void quantize3x3S15Fixed16(double targ[3], double mat[3][3], double in[3]);
+static void icc_setup_wpchtmx(icc *p);
+void icmQuantize3x3S15Fixed16(double targ[3], double mat[3][3], double in[3]);
/* Add any automatically created tags. */
-/* (Hmm. Should we remove them if they shouldn't be there ?) */
-static int icc_add_auto_tags(icc *p) {
+/* Modify white point value if wr is nz. (i.e. in middle of ->write()) */
+/* The 'chad' tag is only added if there is no natural 'chad' tag, */
+/* and will be remove once the write is complete. */
+static int icc_add_auto_tags(icc *p, int wr) {
/* If we're using the ArgyllCMS 'arts' tag to record the chromatic */
/* adapation cone matrix used for the Media Relative WP Transformation, */
/* create it and set it from the wpchtmx[][] matrix. */
- /* Don't write it if there is to 'wtpt' tag (i.e. it's a device link) */
+ /* Don't write it if there is no 'wtpt' tag (i.e. it's a device link) */
if (p->useArts
&& p->find_tag(p, icSigMediaWhitePointTag) == 0) {
int rv;
icmS15Fixed16Array *artsTag;
+ /* Make sure wpchtmx[][] has been set correctly for device class */
+ if (p->wpchtmx_class != p->header->deviceClass) {
+ icc_setup_wpchtmx(p);
+ }
+
/* Make sure no 'arts' tag currently exists */
if (p->delete_tag(p, icmSigAbsToRelTransSpace) != 0
&& p->errc != 2) {
@@ -11889,20 +11912,22 @@ static int icc_add_auto_tags(icc *p) {
return p->errc = 1;
}
- /* The cone matrix is assumed to be arranged conventionaly for matrix */
- /* times vector multiplication. */
- /* Consistent with ICC usage, the dimension corresponding to the matrix */
- /* rows varies least rapidly while the one corresponding to the matrix */
- /* columns varies most rapidly. */
- artsTag->data[0] = p->wpchtmx[0][0];
- artsTag->data[1] = p->wpchtmx[0][1];
- artsTag->data[2] = p->wpchtmx[0][2];
- artsTag->data[3] = p->wpchtmx[1][0];
- artsTag->data[4] = p->wpchtmx[1][1];
- artsTag->data[5] = p->wpchtmx[1][2];
- artsTag->data[6] = p->wpchtmx[2][0];
- artsTag->data[7] = p->wpchtmx[2][1];
- artsTag->data[8] = p->wpchtmx[2][2];
+ if (wr) {
+ /* The cone matrix is assumed to be arranged conventionaly for matrix */
+ /* times vector multiplication. */
+ /* Consistent with ICC usage, the dimension corresponding to the matrix */
+ /* rows varies least rapidly while the one corresponding to the matrix */
+ /* columns varies most rapidly. */
+ artsTag->data[0] = p->wpchtmx[0][0];
+ artsTag->data[1] = p->wpchtmx[0][1];
+ artsTag->data[2] = p->wpchtmx[0][2];
+ artsTag->data[3] = p->wpchtmx[1][0];
+ artsTag->data[4] = p->wpchtmx[1][1];
+ artsTag->data[5] = p->wpchtmx[1][2];
+ artsTag->data[6] = p->wpchtmx[2][0];
+ artsTag->data[7] = p->wpchtmx[2][1];
+ artsTag->data[8] = p->wpchtmx[2][2];
+ }
}
/* If this is a Display profile, and we have been told to save it in */
@@ -11914,20 +11939,22 @@ static int icc_add_auto_tags(icc *p) {
icmS15Fixed16Array *chadTag;
if (p->header->deviceClass == icSigDisplayClass
- && p->useChad
+ && p->wrDChad && !p->naturalChad
&& (whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) != NULL
&& whitePointTag->ttype == icSigXYZType
&& whitePointTag->size >= 1) {
/* If we've set this profile, not just read it, */
/* compute the fromAbs/chad matrix from media white point and cone matrix */
- if (!p->chadValid) {
+ if (!p->chadmxValid) {
double wp[3];
- p->chromAdaptMatrix(p, ICM_CAM_NONE, icmD50, whitePointTag->data[0], p->chadmx);
+ p->chromAdaptMatrix(p, ICM_CAM_NONE, NULL, p->chadmx,
+ icmD50, whitePointTag->data[0]);
/* Optimally quantize chad matrix to preserver white point */
icmXYZ2Ary(wp, whitePointTag->data[0]);
- quantize3x3S15Fixed16(icmD50_ary3, p->chadmx, wp);
+ icmQuantize3x3S15Fixed16(icmD50_ary3, p->chadmx, wp);
+ p->chadmxValid = 1;
}
/* Make sure no 'chad' tag currently exists */
@@ -11948,22 +11975,143 @@ static int icc_add_auto_tags(icc *p) {
sprintf(p->err,"icc_write: Allocating 'chad' tag failed");
return p->errc = 1;
}
+
+ p->tempChad = 1;
- /* Save in ICC matrix order */
- chadTag->data[0] = p->chadmx[0][0];
- chadTag->data[1] = p->chadmx[0][1];
- chadTag->data[2] = p->chadmx[0][2];
- chadTag->data[3] = p->chadmx[1][0];
- chadTag->data[4] = p->chadmx[1][1];
- chadTag->data[5] = p->chadmx[1][2];
- chadTag->data[6] = p->chadmx[2][0];
- chadTag->data[7] = p->chadmx[2][1];
- chadTag->data[8] = p->chadmx[2][2];
+ if (wr) {
+ /* Save in ICC matrix order */
+ chadTag->data[0] = p->chadmx[0][0];
+ chadTag->data[1] = p->chadmx[0][1];
+ chadTag->data[2] = p->chadmx[0][2];
+ chadTag->data[3] = p->chadmx[1][0];
+ chadTag->data[4] = p->chadmx[1][1];
+ chadTag->data[5] = p->chadmx[1][2];
+ chadTag->data[6] = p->chadmx[2][0];
+ chadTag->data[7] = p->chadmx[2][1];
+ chadTag->data[8] = p->chadmx[2][2];
+
+ /* Set 'chad' adhusted white point */
+ p->tempWP = whitePointTag->data[0];
+ whitePointTag->data[0] = icmD50;
+ }
+ }
+ }
- /* Set the media white point to D50 */
- whitePointTag->data[0] = icmD50;
+ /* If this is an Output profile with a non-standard illuminant set, */
+ /* and we have been told to save it using a 'chad' tag to represent */
+ /* the illuminant difference, then adjust the media white point tag */
+ /* for the illuminant, and change the 'chad' tag. */
+ {
+ int rv;
+ icmXYZArray *whitePointTag;
+ icmS15Fixed16Array *chadTag;
+
+ if (p->header->deviceClass == icSigOutputClass
+ && p->chadmxValid
+ && p->wrOChad && !p->naturalChad
+ && (whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) != NULL
+ && whitePointTag->ttype == icSigXYZType
+ && whitePointTag->size >= 1) {
+ double wp[3];
+
+ /* Make sure no 'chad' tag currently exists */
+ if (p->delete_tag(p, icSigChromaticAdaptationTag) != 0
+ && p->errc != 2) {
+ sprintf(p->err,"icc_write: Deleting existing 'chad' tag failed");
+ return p->errc = 1;
+ }
+
+ /* Add one */
+ if ((chadTag = (icmS15Fixed16Array *)p->add_tag(p, icSigChromaticAdaptationTag,
+ icSigS15Fixed16ArrayType)) == NULL) {
+ sprintf(p->err,"icc_write: Adding 'chad' tag failed");
+ return p->errc = 1;
+ }
+ chadTag->size = 9;
+ if ((rv = chadTag->allocate((icmBase *)chadTag) ) != 0) {
+ sprintf(p->err,"icc_write: Allocating 'chad' tag failed");
+ return p->errc = 1;
+ }
+
+ p->tempChad = 1;
+
+ if (wr) {
+ /* Save in ICC matrix order */
+ chadTag->data[0] = p->chadmx[0][0];
+ chadTag->data[1] = p->chadmx[0][1];
+ chadTag->data[2] = p->chadmx[0][2];
+ chadTag->data[3] = p->chadmx[1][0];
+ chadTag->data[4] = p->chadmx[1][1];
+ chadTag->data[5] = p->chadmx[1][2];
+ chadTag->data[6] = p->chadmx[2][0];
+ chadTag->data[7] = p->chadmx[2][1];
+ chadTag->data[8] = p->chadmx[2][2];
+
+ /* Transform white point to take 'chad' into account */
+ p->tempWP = whitePointTag->data[0];
+ icmXYZ2Ary(wp, whitePointTag->data[0]);
+ icmMulBy3x3(wp, p->chadmx, wp);
+ icmAry2XYZ(whitePointTag->data[0], wp);
+ }
}
}
+
+ return 0;
+}
+
+/* Restore profile after creating temporary 'chad' tag, and */
+/* modifying the white point. */
+static int icc_rem_temp_tags(icc *p) {
+
+ /* Restore profile if Display 'chad' has been temporarily added. */
+ {
+ int rv;
+ icmXYZArray *whitePointTag;
+ icmS15Fixed16Array *chadTag;
+
+ if (p->header->deviceClass == icSigDisplayClass
+ && p->tempChad && p->wrDChad && !p->naturalChad
+ && (whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) != NULL
+ && whitePointTag->ttype == icSigXYZType
+ && whitePointTag->size >= 1) {
+
+ /* Remove temporary 'chad' tag */
+ if (p->delete_tag(p, icSigChromaticAdaptationTag) != 0
+ && p->errc != 2) {
+ sprintf(p->err,"icc_write: Deleting temporary 'chad' tag failed");
+ return p->errc = 1;
+ }
+
+ /* Restore original white point */
+ whitePointTag->data[0] = p->tempWP;
+ }
+ }
+
+ /* Restore profile if Output 'chad' has been temporarily added. */
+ {
+ int rv;
+ icmXYZArray *whitePointTag;
+ icmS15Fixed16Array *chadTag;
+
+ if (p->header->deviceClass == icSigOutputClass
+ && p->tempChad && p->wrOChad && !p->naturalChad
+ && (whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) != NULL
+ && whitePointTag->ttype == icSigXYZType
+ && whitePointTag->size >= 1) {
+ double wp[3];
+
+ /* Remove temporary 'chad' tag */
+ if (p->delete_tag(p, icSigChromaticAdaptationTag) != 0
+ && p->errc != 2) {
+ sprintf(p->err,"icc_write: Deleting temporary 'chad' tag failed");
+ return p->errc = 1;
+ }
+
+ /* Restore original white point */
+ whitePointTag->data[0] = p->tempWP;
+ }
+ }
+
return 0;
}
@@ -11977,8 +12125,8 @@ static unsigned int icc_get_size(
) {
unsigned int i, size = 0;
- /* Ignore any errors this time */
- icc_add_auto_tags(p);
+ /* Add 'arts' tag and temporary 'chad' tag if so configured */
+ icc_add_auto_tags(p, 0);
#ifdef ICM_STRICT
/* Check that the right tags etc. are present for a legal ICC profile */
@@ -12039,7 +12187,8 @@ static int icc_write_x(
unsigned int i, size = 0;
unsigned char pbuf[ALIGN_SIZE];
- if ((rv = icc_add_auto_tags(p)) != 0)
+ /* Add 'arts' tag and temporary 'chad' tag and modify white point, if so configured */
+ if ((rv = icc_add_auto_tags(p, 1)) != 0)
return rv;
p->fp = fp; /* Open file pointer */
@@ -12260,6 +12409,10 @@ static int icc_write_x(
p->data[i].objp->touched = 0; /* Written it, so don't write it again. */
}
+ /* Remove any temporary 'chad' tag and restore white point */
+ if ((rv = icc_rem_temp_tags(p)) != 0)
+ return rv;
+
if (p->fp->flush(p->fp) != 0) {
sprintf(p->err,"icc_write flush() failed");
return p->errc = 1;
@@ -12372,6 +12525,10 @@ static icmBase *icc_add_tag(
p->data[p->count].objp = nob; /* Empty object */
p->count++;
+ /* Track whether we have a natural 'chad' tag */
+ if (sig == icSigChromaticAdaptationTag)
+ p->naturalChad = 1;
+
return nob;
}
@@ -12453,6 +12610,10 @@ static icmBase *icc_link_tag(
p->data[exi].objp->refcount++; /* Bump reference count on tag type */
p->count++;
+ /* Track whether we have a natural 'chad' tag */
+ if (sig == icSigChromaticAdaptationTag)
+ p->naturalChad = 1;
+
return p->data[exi].objp;
}
@@ -12657,6 +12818,12 @@ static int icc_rename_tag(
/* change its signature */
p->data[k].sig = sigNew;
+ /* Track whether we have a natural 'chad' tag */
+ if (sig == icSigChromaticAdaptationTag)
+ p->naturalChad = 0;
+ if (sigNew == icSigChromaticAdaptationTag)
+ p->naturalChad = 1;
+
return 0;
}
@@ -12715,7 +12882,6 @@ static int icc_unread_tag(
/* Delete the tag, and free the underlying tag type, */
/* if this was the last reference to it. */
-/* Note this finds the first tag with a matching signature. */
/* Returns non-zero on error: */
/* tag not found - icc->errc will contain 2 */
static int icc_delete_tag_ix(
@@ -12753,6 +12919,7 @@ static int icc_delete_tag(
icTagSignature sig /* Tag signature - may be unknown */
) {
unsigned int i;
+ int rv;
/* Search for signature */
for (i = 0; i < p->count; i++) {
@@ -12764,7 +12931,15 @@ static int icc_delete_tag(
return p->errc = 2;
}
- return icc_delete_tag_ix(p, i);
+ rv = icc_delete_tag_ix(p, i);
+
+ /* Track whether we still have a natural 'chad' tag */
+ if (rv == 0) {
+ if (sig == icSigChromaticAdaptationTag)
+ p->naturalChad = 0;
+ }
+
+ return rv;
}
/* Read all the tags into memory, including unknown types. */
@@ -14971,12 +15146,15 @@ void icmChromAdaptMatrix(
/* We're done */
}
-/* Setup the wpchtmx appropriately for creating profile */
+/* Setup the wpchtmx appropriately for creating profile. */
+/* This is called if the deviceClass has changed on a call */
+/* to ->chromAdaptMatrix(), ->get_size() or ->write(). */
static void icc_setup_wpchtmx(icc *p) {
int useBradford = 1; /* Default use Bradford */
- if (!p->autoWpchtmx)
- return; /* Reading profile has set wpchtmx[][] */
+ /* If set by reading profile or already set appropriately */
+ if (p->wpchtmx_class == p->header->deviceClass)
+ return;
/* If we should use ICC standard Wrong Von Kries for white point chromatic adapation */
if (p->header->deviceClass == icSigOutputClass
@@ -14996,49 +15174,88 @@ static void icc_setup_wpchtmx(icc *p) {
p->wpchtmx_class = p->header->deviceClass;
}
-/* icc Chromatic adaptation transform utility using */
-/* the current Absolute to Media Relative Transformation Space wpchtmx. */
-/* Return a 3x3 chromatic adaptation matrix */
+/* Clear any existing 'chad' matrix, and if Output type profile */
+/* and ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD set and */
+/* ill_wp != NULL, create a 'chad' matrix. */
+static void icc_set_illum(struct _icc *p, double ill_wp[3]) {
+
+ p->chadmxValid = 0; /* Calling set_illum signals profile creation, */
+ /* so discard any previous (i.e. read) chad matrix */
+
+ if (ill_wp != NULL) {
+ icmCpy3(p->illwp, ill_wp);
+ p->illwpValid = 1;
+ }
+
+ /* Is illuminant chromatic adapation chad matrix needed ? */
+ if (p->header->deviceClass == icSigOutputClass
+ && p->illwpValid
+ && p->wrOChad) {
+ double wp[3];
+ icmXYZNumber iwp;
+
+ /* Create Output illuminant 'chad' matrix */
+ icmAry2XYZ(iwp, p->illwp);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, iwp, p->chadmx);
+
+ /* Optimally quantize chad matrix to preserver white point */
+ icmQuantize3x3S15Fixed16(icmD50_ary3, p->chadmx, p->illwp);
+
+ p->chadmxValid = 1;
+ }
+}
+
+/* Return an overall Chromatic Adaptation Matrix for the given source and */
+/* destination white points. This will depend on the icc profiles current setup */
+/* for Abs->Rel conversion (wpchtmx[][] set to wrong Von Kries or not, whether */
+/* 'arts' tag has been read), and whether an Output profile 'chad' tag has bean read */
+/* or will be created. (i.e. on creation, assumes icc->set_illum() called). */
/* Use icmMulBy3x3(dst, mat, src) */
-/* NOTE that to transform primaries they */
-/* must be mat[XYZ][RGB] format! */
-/* NOTE that this resets the chadValid flag (i.e. we assume that if */
-/* this method gets called, that we are discarding any 'chad' tag */
-/* and creating our own chromatic adapation) */
+/* NOTE that to transform primaries they must be mat[XYZ][RGB] format! */
static void icc_chromAdaptMatrix(
icc *p,
- int flags, /* Transform given matrix flag */
- icmXYZNumber d_wp, /* Destination white point */
- icmXYZNumber s_wp, /* Source white point */
- double mat[3][3] /* Destination matrix */
+ int flags, /* ICM_CAM_NONE or ICM_CAM_MULMATRIX to mult by mat */
+ double imat[3][3], /* Optional inverse CAT matrix result */
+ double mat[3][3], /* CAT optional input if ICM_CAM_MULMATRIX & result matrix */
+ icmXYZNumber d_wp, /* Destination white point (Usually PCS D50) */
+ icmXYZNumber s_wp /* Source media absolute white point */
) {
double dst[3], src[3]; /* Source & destination white points */
double vkmat[3][3]; /* Von Kries matrix */
+ double omat[3][3]; /* Output matrix */
if (p->header->deviceClass == icMaxEnumClass) {
fprintf(stderr,"icc_chromAdaptMatrix called with no deviceClass!\n");
}
+ /* Take a copy of src/dst */
+ icmXYZ2Ary(src, s_wp);
+ icmXYZ2Ary(dst, d_wp);
+
/* See if the profile type has changed, re-evaluate wpchtmx */
if (p->wpchtmx_class != p->header->deviceClass) {
icc_setup_wpchtmx(p);
}
/* Set initial matrix to unity if creating from scratch */
- if (!(flags & ICM_CAM_MULMATRIX)) {
- icmSetUnity3x3(mat);
- }
+ if (flags & ICM_CAM_MULMATRIX)
+ icmCpy3x3(omat, mat);
+ else
+ icmSetUnity3x3(omat);
- /* Take a copy of src/dst */
- icmXYZ2Ary(src, s_wp);
- icmXYZ2Ary(dst, d_wp);
+ /* Incorporate Output chad matrix if we will be creating one */
+ if (p->header->deviceClass == icSigOutputClass
+ && p->chadmxValid) {
+ icmMulBy3x3(src, p->chadmx, src);
+ icmMul3x3(omat, p->chadmx);
+ }
/* Transform src/dst to cone space */
icmMulBy3x3(src, p->wpchtmx, src);
icmMulBy3x3(dst, p->wpchtmx, dst);
- /* Transform incoming matrix cone space */
- icmMul3x3(mat, p->wpchtmx);
+ /* Transform incoming matrix to cone space */
+ icmMul3x3(omat, p->wpchtmx);
/* Setup the Von Kries white point adaptation matrix */
vkmat[0][0] = dst[0]/src[0];
@@ -15049,14 +15266,16 @@ static void icc_chromAdaptMatrix(
vkmat[2][0] = vkmat[2][1] = 0.0;
/* Apply chromatic adaptation */
- icmMul3x3(mat, vkmat);
+ icmMul3x3(omat, vkmat);
/* Transform from con space */
- icmMul3x3(mat, p->iwpchtmx);
+ icmMul3x3(omat, p->iwpchtmx);
- p->chadValid = 0; /* Don't use this now */
+ if (mat != NULL)
+ icmCpy3x3(mat, omat);
- /* We're done */
+ if (imat != NULL)
+ icmInverse3x3(imat, omat);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -15143,7 +15362,7 @@ int icmRGBYxyprim2matrix(
/* the matrix and the input value is the same as */
/* the quantized matrix product. This is used to improve accuracy */
/* of 'chad' tag in computing absolute white point. */
-void quantize3x3S15Fixed16(
+void icmQuantize3x3S15Fixed16(
double targ[3], /* Target of product */
double mat[3][3], /* matrix[][] to be quantized */
double in[3] /* Input of product - must not be 0.0! */
@@ -15491,7 +15710,7 @@ void icmRec709_50_YPbPr_2_RGBd(double out[3], double in[3]) {
}
-/* Convert Rec2020 RGB' into Non-constant liminance YPbPr, or "full range YCbCr" */
+/* Convert Rec2020 RGB' into Non-constant luminance YPbPr, or "full range YCbCr" */
/* where input 0..1, output 0..1, -0.5 .. 0.5, -0.5 .. 0.5 */
/* [From the Rec2020 specification] */
void icmRec2020_NCL_RGBd_2_YPbPr(double out[3], double in[3]) {
@@ -15512,7 +15731,7 @@ void icmRec2020_NCL_RGBd_2_YPbPr(double out[3], double in[3]) {
out[2] = tt[2];
}
-/* Convert Rec2020 Non-constant liminance YPbPr into RGB' (== "full range YCbCr") */
+/* Convert Rec2020 Non-constant luminance YPbPr into RGB' (== "full range YCbCr") */
/* where input 0..1, -0.5 .. 0.5, -0.5 .. 0.5, output 0.0 .. 1 */
/* [Inverse of above] */
void icmRec2020_NCL_YPbPr_2_RGBd(double out[3], double in[3]) {
@@ -15527,7 +15746,7 @@ void icmRec2020_NCL_YPbPr_2_RGBd(double out[3], double in[3]) {
out[2] = tt[2];
}
-/* Convert Rec2020 RGB' into Constant liminance YPbPr, or "full range YCbCr" */
+/* Convert Rec2020 RGB' into Constant luminance YPbPr, or "full range YCbCr" */
/* where input 0..1, output 0..1, -0.5 .. 0.5, -0.5 .. 0.5 */
/* [From the Rec2020 specification] */
void icmRec2020_CL_RGBd_2_YPbPr(double out[3], double in[3]) {
@@ -15568,7 +15787,7 @@ void icmRec2020_CL_RGBd_2_YPbPr(double out[3], double in[3]) {
out[2] = tt[2];
}
-/* Convert Rec2020 Constant liminance YPbPr into RGB' (== "full range YCbCr") */
+/* Convert Rec2020 Constant luminance YPbPr into RGB' (== "full range YCbCr") */
/* where input 0..1, -0.5 .. 0.5, -0.5 .. 0.5, output 0.0 .. 1 */
/* [Inverse of above] */
void icmRec2020_CL_YPbPr_2_RGBd(double out[3], double in[3]) {
@@ -16278,13 +16497,14 @@ struct _icmLuBase *lup
lup->blackisassumed = 0; /* The black is from the tag */
}
- /* If this is a Display profile, check if there is a 'chad' tag, and setup the */
- /* white point and toAbs/fromAbs matricies from that, so as to implement an */
+ /* If this is a Display profile, check if there is a 'chad' tag, then */
+ /* setup the white point and toAbs/fromAbs matricies from that, so as to implement an */
/* effective Absolute Colorimetric intent for such profiles. */
if (p->header->deviceClass == icSigDisplayClass
- && p->chadValid) {
+ && p->naturalChad && p->chadmxValid) {
double wp[3];
+ /* Conversion matrix is chad matrix. */
icmCpy3x3(lup->fromAbs, p->chadmx);
icmInverse3x3(lup->toAbs, lup->fromAbs);
@@ -16300,10 +16520,28 @@ struct _icmLuBase *lup
DBLLL(("computed wp %.8f %.8f %.8f\n", lup->whitePoint.X,
lup->whitePoint.Y, lup->whitePoint.Z));
+ /* If this is an Output profile, check if there is a 'chad' tag, and */
+ /* setup the toAbs/fromAbs matricies so that they include it, so as to implement an */
+ /* effective Absolute Colorimetric intent for such profiles. */
+ } else if (p->header->deviceClass == icSigOutputClass
+ && p->naturalChad && p->chadmxValid) {
+ double wp[3];
+ double ichad[3][3];
+
+ /* Convert the white point tag value backwards through the 'chad' */
+ icmXYZ2Ary(wp, lup->whitePoint);
+ icmInverse3x3(ichad, p->chadmx);
+ icmMulBy3x3(wp, ichad, wp);
+ icmAry2XYZ(lup->whitePoint, wp);
+
+ /* Create absolute <-> relative conversion matricies */
+ p->chromAdaptMatrix(p, ICM_CAM_NONE, lup->toAbs, lup->fromAbs, icmD50, lup->whitePoint);
+ DBLLL(("toAbs and fromAbs created from 'chad' tag & WP tag\n"));
+ DBLLL(("toAbs and fromAbs created from wp %f %f %f and D50 %f %f %f\n", lup->whitePoint.X,
+ lup->whitePoint.Y, lup->whitePoint.Z, icmD50.X, icmD50.Y, icmD50.Z));
} else {
/* Create absolute <-> relative conversion matricies */
- p->chromAdaptMatrix(p, ICM_CAM_NONE, lup->whitePoint, icmD50, lup->toAbs);
- p->chromAdaptMatrix(p, ICM_CAM_NONE, icmD50, lup->whitePoint, lup->fromAbs);
+ p->chromAdaptMatrix(p, ICM_CAM_NONE, lup->toAbs, lup->fromAbs, icmD50, lup->whitePoint);
DBLLL(("toAbs and fromAbs created from wp %f %f %f and D50 %f %f %f\n", lup->whitePoint.X,
lup->whitePoint.Y, lup->whitePoint.Z, icmD50.X, icmD50.Y, icmD50.Z));
}
@@ -18935,6 +19173,7 @@ icmAlloc *al /* Memory allocator */
p->get_tac = icm_get_tac;
p->get_luobj = icc_get_luobj;
p->new_clutluobj = icc_new_icmLuLut;
+ p->set_illum = icc_set_illum;
p->chromAdaptMatrix = icc_chromAdaptMatrix;
#if defined(__IBMC__) && defined(_M_IX86)
@@ -18984,30 +19223,39 @@ icmAlloc *al /* Memory allocator */
for (i = 0; i < 16; i++)
p->header->id[i] = 0;
- p->autoWpchtmx = 1; /* Auto on create */
-
/* Should we use ICC standard Wrong Von Kries for */
/* white point chromatic adapation for output class ? */
if (getenv("ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP") != NULL)
p->useLinWpchtmx = 1; /* Use Wrong Von Kries */
else
p->useLinWpchtmx = 0; /* Use Bradford by default */
- p->wpchtmx_class = icMaxEnumClass; /* Not set yet */
+ p->wpchtmx_class = icMaxEnumClass; /* Not set yet - auto set on create. */
/* Default to saving ArgyllCMS private 'arts' tag (if appropriate type of */
/* profile) to make white point chromatic adapation explicit. */
p->useArts = 1;
/* Should we create a V4 style Display profile with D50 media white point */
- /* tag and 'chad' tag ? */
+ /* tag and 'chad' tag ? - or - */
+ /* Should we create an Output profile using a 'chad' tag if it uses */
+ /* a non-standard illuminant ? */
if (getenv("ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD") != NULL)
- p->useChad = 1; /* Mark Media WP as D50 and put absolute to relative */
- /* transform matrix in 'chad' tag. */
+ p->wrDChad = 1; /* For Display profile mark media WP as D50 and put */
+ /* absolute to relative transform matrix in 'chad' tag. */
+ else
+ p->wrDChad = 0; /* No by default - use Bradford and store real Media WP */
+
+ /* Should we create an Output profile using a 'chad' tag if it uses */
+ /* a non-standard illuminant ? */
+ if (getenv("ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD") != NULL)
+ p->wrOChad = 1; /* For Output profile, put illuminant to D50 Bradford */
+ /* matrix in 'chad' tag, and transform real WP by it. */
else
- p->useChad = 0; /* No by default - use Bradford and store real Media WP */
+ p->wrOChad = 0; /* No by default - Media WP inclues effect of illuminant. */
/* Set a default wpchtmx in case the profile being read or written */
/* doesn't use a white point (i.e., it's a device link) */
+ /* This will be reset if the wpchtmx_class gets changed. */
if (!p->useLinWpchtmx) {
icmCpy3x3(p->wpchtmx, icmBradford);
icmInverse3x3(p->iwpchtmx, p->wpchtmx);
diff --git a/icc/icc.h b/icc/icc.h
index 36ec73a..e0bf88e 100644
--- a/icc/icc.h
+++ b/icc/icc.h
@@ -11,7 +11,7 @@
* Copyright 1997 - 2013 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/* We can get some subtle errors if certain headers aren't included */
@@ -30,8 +30,8 @@
/* Version of icclib release */
-#define ICCLIB_VERSION 0x020020
-#define ICCLIB_VERSION_STR "2.20"
+#define ICCLIB_VERSION 0x020021
+#define ICCLIB_VERSION_STR "2.21"
#undef ENABLE_V4 /* V4 is not fully implemented */
@@ -74,14 +74,16 @@
/* so long shouldn't really be used in any code.... */
/* (duplicated in icc.h) */
-/* Use __LP64__ as cross platform 64 bit pointer #define */
-#if !defined(__LP64__) && defined(_WIN64)
-# define __LP64__ 1
+/* Use __P64__ as cross platform 64 bit pointer #define */
+#if defined(__LP64__) || defined(__ILP64__) || defined(__LLP64__) || defined(_WIN64)
+# define __P64__ 1
#endif
#ifndef ORD32 /* If not defined elsewhere */
-#if (__STDC_VERSION__ >= 199901L) /* C99 */
+#if (__STDC_VERSION__ >= 199901L) /* C99 */ \
+ || defined(_STDINT_H_) || defined(_STDINT_H) \
+ || defined(_SYS_TYPES_H)
#include <stdint.h>
@@ -100,7 +102,11 @@
#define CF64PREC "LL" /* Constant precision specifier */
#ifndef ATTRIBUTE_NORETURN
-# define ATTRIBUTE_NORETURN __declspec(noreturn)
+# ifdef _MSC_VER
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+# else
+# define ATTRIBUTE_NORETURN __attribute__((noreturn))
+# endif
#endif
#else /* !__STDC_VERSION__ */
@@ -141,7 +147,7 @@
#define ORD32 unsigned int /* 32 bit unsigned */
#ifdef __GNUC__
-# ifdef __LP64__ /* long long could be 128 bit */
+# ifdef __LP64__ /* long long could be 128 bit ? */
# define INR64 long /* 64 bit signed - not used in icclib */
# define ORD64 unsigned long /* 64 bit unsigned - not used in icclib */
# define PF64PREC "l" /* printf format precision specifier */
@@ -1493,15 +1499,30 @@ struct _icc {
int (*delete_tag)(struct _icc *p, icTagSignature sig);
/* Returns 0 if deleted OK */
int (*check_id)(struct _icc *p, ORD8 *id); /* Returns 0 if ID is OK, 1 if not present etc. */
- double (*get_tac)(struct _icc *p, double *chmax, /* Returns total ink limit and channel maximums */
- void (*calfunc)(void *cntx, double *out, double *in), void *cntx);
- /* optional cal. lookup */
- void (*chromAdaptMatrix)(struct _icc *p, int flags, icmXYZNumber d_wp,
- icmXYZNumber s_wp, double mat[3][3]);
- /* Chromatic transform function that uses icc */
- /* Absolute to Media Relative Transformation Space matrix */
- /* Set header->deviceClass before calling this! */
-
+ double (*get_tac)(struct _icc *p, double *chmax,
+ void (*calfunc)(void *cntx, double *out, double *in), void *cntx);
+ /* Returns total ink limit and channel maximums */
+ /* calfunc is optional. */
+ void (*set_illum)(struct _icc *p, double ill_wp[3]);
+ /* Clear any existing 'chad' matrix, and if Output type profile */
+ /* and ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD set and */
+ /* ill_wp != NULL, create a 'chad' matrix. */
+ void (*chromAdaptMatrix)(struct _icc *p, int flags, double imat[3][3],
+ double mat[3][3], icmXYZNumber d_wp, icmXYZNumber s_wp);
+ /* Return an overall Chromatic Adaptation Matrix */
+ /* for the given source and destination white points. */
+ /* This will depened on the icc profiles current setup */
+ /* for Abs->Rel conversion (wpchtmx[][] set to wrong Von */
+ /* Kries or not, whether 'arts' tag has been read), and */
+ /* whether an Output profile 'chad' tag has bean read */
+ /* or will be created. (i.e. on writing assumes */
+ /* icc->set_illum() called or not). */
+ /* Set header->deviceClass before calling this! */
+ /* ICM_CAM_NONE or ICM_CAM_MULMATRIX to mult by mat. */
+ /* Return invers of matrix if imat != NULL. */
+ /* Use icmMulBy3x3(dst, mat, src). */
+ /* NOTE that to transform primaries they */
+ /* must be mat[XYZ][RGB] format! */
/* Get a particular color conversion function */
icmLuBase * (*get_luobj) (struct _icc *p,
@@ -1531,27 +1552,57 @@ struct _icc {
int errc; /* Error code */
int warnc; /* Warning code */
+ /* - - - - - - - - tweaks - - - - - - - */
int allowclutPoints256; /* Non standard - allow 256 res cLUT */
- int autoWpchtmx; /* Whether to automatically set wpchtmx[][] based on */
- /* the header and the state of the env override */
- /* ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP. */
- /* Default true, set false on reading a profile. */
int useLinWpchtmx; /* Force Wrong Von Kries for output class (default false) */
- icProfileClassSignature wpchtmx_class; /* Class of profile wpchtmx was set for */
- double wpchtmx[3][3]; /* Absolute to Media Relative Transformation Space matrix */
+ /* Could be set by code, and is set set by */
+ /* ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP env. */
+ icProfileClassSignature wpchtmx_class; /* Class of profile wpchtmx was set for. */
+ /* Set wpchtmx automatically on ->chromAdaptMatrix() */
+ /* or ->get_size() or ->write() if the profile class */
+ /* doesn't match wpchtmx_class. */
+ double wpchtmx[3][3]; /* Absolute to Media Relative Transformation Space (i.e. */
+ /* Cone Space transformation) matrix. */
double iwpchtmx[3][3]; /* Inverse of wpchtmx[][] */
/* (Default is Bradford matrix) */
- int useArts; /* Save ArgyllCMS private 'arts' tag (default yes) */
- /* (This creates 'arts' tag on writing) */
-
- int chadValid; /* nz if 'chad' tag has been read and chadmx is valid */
- double chadmx[3][3]; /* 'chad' tag matrix if read */
- int useChad; /* Create 'chad' tag for Display profile (default no) */
- /* Override with ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD */
- /* (This set media white point tag to D50 and */
- /* creates 'chad' tag on writing) */
-
+ int useArts; /* Save ArgyllCMS private 'arts' tag (default yes). */
+ /* This creates 'arts' tag on writing. */
+ /* This is cleared if 'arts' tag is not found on reading. */
+
+ double illwp[3]; /* Output type profile illuminant white point, */
+ /* used to create 'chad' tag if */
+ /* ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD is set. */
+ int illwpValid; /* illwp[] has been set. */
+
+ int naturalChad; /* nz if 'chad' tag is naturally present in the profile, */
+ /* because it was read or added. wrD/OChad will be */
+ /* ignored if this is the case. */
+
+ int chadmxValid; /* nz if 'chad' tag has been read, or created */
+ /* using ->set_illum() and chadmx is valid. */
+ double chadmx[3][3]; /* 'chad' tag matrix if read or created. */
+ /* (This is used to restore full absolute intent for */
+ /* Display and Output type profiles.) */
+
+ int wrDChad; /* Create 'chad' tag for Display profiles (default no). */
+ /* Override with ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD. */
+ /* On writing Display profiles this sets the media white */
+ /* point tag to D50 and creates 'chad' tag from the white */
+ /* point to D50. Ignored if naturalChad. */
+
+ int wrOChad; /* Create 'chad' tag for Output profiles (default no). */
+ /* Override with ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD. */
+ /* On writing an Output profile, this Creates a 'chad' */
+ /* tag frp, illwp[] to D50, and sets the white point */
+ /* tag to be the real value transformed by the */
+ /* 'chad' matrix. Ignored if naturalChad. */
+
+ int tempChad; /* nz while temporary chad tag is in place and */
+ /* white point has been modified, between */
+ /* ->get_size() to ->write() calls when wrD/OChad active. */
+ icmXYZNumber tempWP; /* Save real wp tag value here between ->get_size() */
+ /* to ->write() calls when wrD/OChad active. */
/* Private: ? */
icmAlloc *al; /* Heap allocator */
@@ -2082,7 +2133,8 @@ int icmRGBYxyprim2matrix(
/* Chromatic Adaption transform utility */
/* Return a 3x3 chromatic adaption matrix */
/* Use icmMulBy3x3(dst, mat, src) */
-/* [ use icc->chromAdaptMatrix() to use the profiles cone space matrix] */
+/* [ use icc->chromAdaptMatrix() to use the profiles cone space matrix rather */
+/* than specify a CAM ] */
#define ICM_CAM_NONE 0x0000 /* No flags */
#define ICM_CAM_BRADFORD 0x0001 /* Use Bradford sharpened response space */
@@ -2105,6 +2157,16 @@ void quantizeRGBprimsS15Fixed16(
double mat[3][3] /* matrix[RGB][XYZ] */
);
+/* Pre-round a 3x3 matrix to ensure that the product of */
+/* the matrix and the input value is the same as */
+/* the quantized matrix product. This is used to improve accuracy */
+/* of 'chad' tag in computing absolute white point. */
+void icmQuantize3x3S15Fixed16(
+ double targ[3], /* Target of product */
+ double mat[3][3], /* matrix[][] to be quantized */
+ double in[3] /* Input of product - must not be 0.0! */
+);
+
/* - - - - - - - - - - - - - - */
/* Video functions */
diff --git a/icc/iccV42.h b/icc/iccV42.h
index 2f3ec27..a84f79d 100644
--- a/icc/iccV42.h
+++ b/icc/iccV42.h
@@ -17,7 +17,7 @@
*
* Portions of this file are Copyright 2004 - 2005 Graeme W. Gill,
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*
* Graeme Gill.
*/
diff --git a/icc/iccdump.c b/icc/iccdump.c
index 76959e7..8574258 100644
--- a/icc/iccdump.c
+++ b/icc/iccdump.c
@@ -10,7 +10,7 @@
* Copyright 1997 - 2012 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/*
diff --git a/icc/icclu.c b/icc/icclu.c
index 80126da..5c732d0 100644
--- a/icc/icclu.c
+++ b/icc/icclu.c
@@ -10,7 +10,7 @@
* Copyright 1998 - 2012 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/* TTBD:
diff --git a/icc/iccrw.c b/icc/iccrw.c
index 807c5f4..f33c164 100644
--- a/icc/iccrw.c
+++ b/icc/iccrw.c
@@ -10,7 +10,7 @@
* Copyright 1997 - 2012 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/* TTBD:
diff --git a/icc/iccstd.c b/icc/iccstd.c
index 1cb63eb..6629250 100644
--- a/icc/iccstd.c
+++ b/icc/iccstd.c
@@ -9,7 +9,7 @@
* Copyright 1997 - 2012 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*
* These are kept in a separate file to allow them to be
* selectively ommitted from the icc library.
diff --git a/icc/icctest.c b/icc/icctest.c
index d04cc1e..647ba07 100644
--- a/icc/icctest.c
+++ b/icc/icctest.c
@@ -10,7 +10,7 @@
* Copyright 1997 - 2012 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/* TTBD:
diff --git a/icc/log.txt b/icc/log.txt
index 2e185dc..b531f5c 100644
--- a/icc/log.txt
+++ b/icc/log.txt
@@ -1,6 +1,10 @@
Change History: (See ArgyllCMS log.txt too)
+ 2.21
+ Automatically repair icmTextDescription strings have an allocation that is longer
+ than their size.
+
2.20
Add better cross compatibility with non-Argyll ICC profiles:
+ Use "wrong Von Kries" media white point adapation for non-Argyll non-display profile
diff --git a/icc/lutest.c b/icc/lutest.c
index 9bf127f..fb05ea9 100644
--- a/icc/lutest.c
+++ b/icc/lutest.c
@@ -10,7 +10,7 @@
* Copyright 1998 - 2012 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/* TTBD:
diff --git a/icc/mcheck.c b/icc/mcheck.c
index a392f31..51368ca 100644
--- a/icc/mcheck.c
+++ b/icc/mcheck.c
@@ -10,7 +10,7 @@
* Copyright 2000 - 2012 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*/
/* TTBD:
diff --git a/icc/mkDispProf.c b/icc/mkDispProf.c
index 6878aad..b7c32c6 100644
--- a/icc/mkDispProf.c
+++ b/icc/mkDispProf.c
@@ -10,7 +10,7 @@
* Copyright 2006 - 2014 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
- * see the License.txt file in this directory for licensing details.
+ * see the License4.txt file in this directory for licensing details.
*
* Based on icc/lutest.c
*/
@@ -267,7 +267,7 @@ char *argv[]
/* Convert to D50 adapated */
icmAry2XYZ(white, wrgb[0]);
- wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_NONE, icmD50, white, fromAbs);
+ wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_NONE, NULL, fromAbs, icmD50, white);
icmMulBy3x3(d50m[0], fromAbs, mat[0]);
icmMulBy3x3(d50m[1], fromAbs, mat[1]);
icmMulBy3x3(d50m[2], fromAbs, mat[2]);
diff --git a/icc/sRGB.icm b/icc/sRGB.icm
index 9d33a4b..59b4507 100644
--- a/icc/sRGB.icm
+++ b/icc/sRGB.icm
Binary files differ
diff --git a/imdi/cctiff.c b/imdi/cctiff.c
index 32dc5e8..582f2ad 100644
--- a/imdi/cctiff.c
+++ b/imdi/cctiff.c
@@ -96,7 +96,6 @@
#include "icc.h"
#include "xicc.h"
#include "imdi.h"
-#include "ui.h"
#undef DEBUG /* Print detailed debug info */
diff --git a/imdi/greytiff.c b/imdi/greytiff.c
index bcc7553..af52013 100644
--- a/imdi/greytiff.c
+++ b/imdi/greytiff.c
@@ -42,7 +42,6 @@
#include "numlib.h"
#include "xicc.h"
#include "imdi.h"
-#include "ui.h"
#undef DO_CHECK /* Do floating point check */
diff --git a/imdi/itest.c b/imdi/itest.c
index 515d2b1..8edcb8b 100644
--- a/imdi/itest.c
+++ b/imdi/itest.c
@@ -16,7 +16,6 @@
#include "numlib.h"
#include "imdi.h"
#include "refi.h"
-#include "ui.h"
/* Test parameters */
#undef TEST1 /* Test just one combination */
diff --git a/link/collink.c b/link/collink.c
index 597cd1d..dffa8df 100644
--- a/link/collink.c
+++ b/link/collink.c
@@ -176,7 +176,6 @@
#include "gamut.h"
#include "gammap.h"
#include "vrml.h"
-#include "ui.h"
void usage(char *diag, ...) {
int i;
@@ -1281,10 +1280,10 @@ void devip_devop(void *cntx, double *out, double *in) {
/* Abstract profile transform, PCS -> PCS */
/* pcsor -> abstract -> pcsor conversion */
/* We're applying any abstract profile after gamut mapping, */
- /* on the assumption is is primarily being used to "correct" the */
+ /* on the assumption is primarily being used to "correct" the */
/* output device. Ideally the gamut mapping should take the change */
/* the abstract profile has on the output device into account, but */
- /* currently we're not doing this.. */
+ /* currently we're not doing this... */
if (wptrig == 0 && p->abs_luo != NULL) {
/* Abstract profile is either absolute or relative. */
/* We need to convert the current PCS into something compatible. */
@@ -3620,7 +3619,7 @@ main(int argc, char *argv[]) {
printf(" Creating Gamut match\n");
li.map = new_gammap(li.verb, csgam, igam, ogam, &li.gmi,
- li.src_kbp, li.dst_kbp, li.cmyhack, li.rel_oride,
+ NULL, li.src_kbp, li.dst_kbp, li.cmyhack, li.rel_oride,
mapres, NULL, NULL, li.gamdiag ? "gammap" : NULL
);
if (li.map == NULL)
@@ -3631,7 +3630,7 @@ main(int argc, char *argv[]) {
printf(" Creating K only black to K only black Gamut match\n");
li.Kmap = new_gammap(li.verb, csgam, igam, ogam, &li.gmi,
- 1, 1, li.cmyhack, li.rel_oride,
+ NULL, 1, 1, li.cmyhack, li.rel_oride,
mapres, NULL, NULL, li.gamdiag ? "gammap" : NULL
);
if (li.Kmap == NULL)
diff --git a/log.txt b/log.txt
index e94a676..b203f57 100644
--- a/log.txt
+++ b/log.txt
@@ -2,7 +2,160 @@
Argyll CMS change log
=====================
-Version 1.8.3
+Version 1.9.1 28th September 2016
+-------------
+
+* Added some diagnostics to ChromeCast discovery, and increased mDNS
+ TTL count and wait time.
+
+* Fixed regression on MSWindows systems with no serial ports.
+
+Version 1.9.0 26th September 2016
+-------------
+
+* Added smoothing filter to pre-conditioning profile lookup in
+ target/targen/ofps.c, to improve its robustness when faced with
+ more poorly behaved profiles.
+
+* Fixed oeminst so that it locates cdrom's in Linuxes latest
+ mount point of /run/media/$USER/.
+ (Who can guess where it will move to next ? What's a stable API again ??)
+
+* Fixed bug in i1pro2 driver, in which strip calibration would
+ fail if instrument had been first calibrated with ARGYLL_DISABLE_I1PRO2_DRIVER
+ set, and then calibrated with ARGYLL_DISABLE_I1PRO2_DRIVER unset.
+ This was due to an incompatible minimum integration time being saved and
+ then restored in the .cal file.
+
+* Fixed bug with i1pro2 (Rev E), where on OS X it would always operate
+ in Rev A-D (i1pro 1) mode.
+
+* Fixed problems with serial connected & USB serial
+ instrument discovery, particularly with the Spectroscan.
+
+* Enhanced spec2cie to process .sp files as well as .ti3.
+
+* Added measurement type to .sp file format, to more inteligently
+ interpret such files in specplot.
+
+* Added option to icclib to write Output profiles using
+ 'chad' tag if the ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD
+ environment variable is set. This is not recommended
+ for normal use, but may assist compatibility with other
+ systems.
+
+* Added JETI spectraval (1511, 1501) support, including Bluetooth access.
+
+* Added support for the Klein K10 connecting via a serial port.
+
+* Fixed bug in Colormunki Smile driver that causes crash
+ on Ubuntu 16.04.1 LTS.
+
+* Fixed problem with targen -g, in that the corresponding XYZ
+ values had double the power applied, rather than none. This
+ was causing problems with printtarg spacer colors.
+
+* Modified instlib API slightly, to improve ease of internationalization.
+
+* Modified "lp" intent to greatly reduce Helmholtz-Kohlrausch appearance
+ modelling.
+
+* Added -V option to xicclu to allow looking up or plotting 'vcgt'
+ tag calibration curves.
+
+* Fixed webwin and oeminst web interface headers (Thanks to Florian Hoech).
+
+* Extensive re-write of colorimetric nearest clipping code in rspl/rev.c
+ to restore precision that was lost in the speedups made
+ in V1.0.0. The nnrev setup now takes a lot longer with
+ high resolution CMYK profiles though. This corrects a
+ "green becomming too yellow" problem for mapping from
+ ProPhoto space with some RGB devices. Added LCh nearest
+ clip mapping weighting values to allow fine tuning of
+ clipping behaviour to better match peoples expectations.
+
+* Change dispwin to properly set DirectColor and take account
+ of TrueColor Colormap. This fixes problem with NVidia linux driver 364.12
+ exposing a VideoLUT depth that is different from the frame buffer depth.
+ Also changed the VideoLut test patch set code to load the same input
+ value either side of the expected one, to allow a margin for any imprecision
+ or difference in how the hardware actually processes frame buffer output.
+
+* Change icclib to automatically repair icmTextDescription strings that
+ have an allocation that is longer than their size.
+
+* Added -e option to average, to use per-component
+ Median rather than average.
+
+* Fixed chartread so that it doesn't fail if no
+ instruments are found when -x option is used.
+
+* Added i1Pro Lamp Drift test and fix functions to
+ spotread (-Y l|L options).
+
+* Fixed bug in gammap.c that sometimes causes crash when
+ using colprof -s -S general compression ratio.
+
+* Add -x parameter to iccgamut and tiffgamut, to create a cylindrically
+ expanded gamut. This can be used to emulate the colprof -s/-S compression
+ percentage when using collink.
+
+* Change colprof so that -s -S will accept general compression percentage
+ as an alternative to a source colorspace/image gamut.
+
+* Added optional conversion from native Gretag-MacBeth & X-Rite
+ reflective calibration standards to/from XRGA.
+
+* Changed OS X GUI support code so as not to switch to
+ "interact with the Dock" mode until actual GUI element
+ is to be displayed. This prevents batch commands with optional
+ GUI elements from blocking normal GUI interactions.
+
+* Re-jigged OS X UI code to use the main thread to avoid
+ window creation timing issues and a warning backtrace on OS X 10.11.
+
+* Add UI synchronization code into OS X test patch display,
+ to ensure test window is displayed before measurements start.
+
+* Added CMP_Digital_Target-7.cht
+
+* Fix spec2cie to cope with .ti3 files that are missing
+ device values, so that it can process a wider range of
+ input CIE reference files.
+
+* Make ColorMunki spectro do "reset on close" on Linux
+ to avoid USB problem every second time it is opened.
+
+* Remove oeminst diagnostic code that writes "temp.cab" file.
+
+* Fix crash in ccxxmake.
+
+* Changed implementation of ARGYLL_NOT_INTERACTIVE on MSWin
+ to make it more reliable when operated progromatically.
+
+* Fix bug in how colverify was computing worst 10% average.
+
+* Fixed chartread so that if you are reading patch by patch,
+ the location strings can be arbitrary (i.e. they don't
+ have to conform to an alpha/num strip/patch pattern.)
+
+* Added Current Aprox. Gamma to displcal Display adjustment menu Check All
+ output.
+
+* Fix dispcal "icc_chromAdaptMatrix called with no deviceClass" warning
+ when creating a matrix display profile.
+
+* Fix colprof eronious "FWA compensation ignored for emissive" warning.
+
+* Fix debug system info being printed, even with no debug option.
+
+* Made DTP92/94 driver ignore Offset drift calibration checksum failed
+ error for Set to factory calibration command as well as reset.
+
+* Added support for Sencore ColorPro V, IV & III colorimeters
+ (based on Sequel Chroma colorimeter.)
+
+Version 1.8.3 (26 October 2015)
-------------
* Added SpyderCheckr24 scaning .cht and .cie files.
@@ -55,7 +208,7 @@ Version 1.8.3
* Reduced the level of Helmholtz-Kohlrausch effect in CIECAM02
implementation in the light of visual experiments.
-Version 1.8.2
+Version 1.8.2 (7th September 2015)
-------------
* Fixed endless loop bug in alternate calibration selectors code.
@@ -2371,7 +2524,7 @@ Version 1.0.0 changes (1st July 2008)
Changed aceleration grids to only hold fwd cells that
are within the ink limit. Changes sub-simplex handling
to make common face sub-simplexes shared between cells.
- Fixed bug in ink limit bug that was causing many sub-simplexes
+ Fixed bug in ink limit that was causing many sub-simplexes
to be treated as if they straddled the ink boundary, slowing
down inversions with ink limits applied. Changed reverse
memory size accounting from cells to bytes, for more
diff --git a/makepackagebin.sh b/makepackagebin.sh
index 2b846ba..0b88664 100644
--- a/makepackagebin.sh
+++ b/makepackagebin.sh
@@ -3,6 +3,9 @@ echo "Script to invoke Jam and then package the binary release."
# Must use this rather than "jam -q" to ensure builtin libraries are used.
+# Set the environment string VERSION from the #define, ie 1.0.0
+VERSION=`grep ARGYLL_VERSION_STR h/aconfig.h | head -1 | sed 's/# define ARGYLL_VERSION_STR //' | sed 's/"//g'`
+
# Typical environment variables:
# (NOTE some systems don't export these ENV vars. by default !!!)
#
@@ -33,10 +36,7 @@ echo "Script to invoke Jam and then package the binary release."
# FreeBSD 9.1 64 bit [bash] freebsd9.1 amd64-portbld-freebsd9.1 amd64
#
-# Set the environment string VERSION from the #define, ie 1.0.0
-VERSION=`grep ARGYLL_VERSION_STR h/aconfig.h | sed 's/#define ARGYLL_VERSION_STR //' | sed 's/"//g'`
-
-echo "About to make Argyll binary distribution"
+echo "About to make Argyll binary distribution $VERSION"
TOPDIR=Argyll_V$VERSION
@@ -47,6 +47,7 @@ fi
# Make sure that some environment variable are visible to Jam:
export OSTYPE MACHTYPE HOSTTYPE
+unset USETARPREFIX
# .sp come from profile, .cht from scanin and .ti3 from spectro
rm -f bin/*.exe bin/*.dll
@@ -104,6 +105,7 @@ else if [ X$OSTYPE = "Xdarwin10.0" \
USBDIRS="usb"
USBBINFILES="binfiles.osx"
USETAR=true
+ USETARPREFIX=true
else if [ X$OSTYPE = "Xlinux-gnu" ] ; then
if [[ "$MACHTYPE" = x86_64-*-linux-gnu ]] ; then
echo "We're on Linux x86_64!"
@@ -160,7 +162,12 @@ done
# Create the package
rm -f $PACKAGE
if [ X$USETAR = "Xtrue" ] ; then
- tar -czvf $PACKAGE $TOPDIR
+ if [ X$USETARPREFIX = "Xtrue" ] ; then
+ # Don't save ._* files...
+ COPYFILE_DISABLE=1 tar -czvf $PACKAGE $TOPDIR
+ else
+ tar -czvf $PACKAGE $TOPDIR
+ fi
# tar -xzf to extract
# tar -tzf to list
# Should we use "COPYFILE_DISABLE=1 tar .." on OS X ??
diff --git a/numlib/numsup.c b/numlib/numsup.c
index c08ed99..39011ae 100644
--- a/numlib/numsup.c
+++ b/numlib/numsup.c
@@ -51,6 +51,7 @@ char *exe_path = "\000"; /* Directory executable resides in ('/' dir separator
//char *error_program = "Unknown"; /* Name to report as responsible for an error */
static int g_log_init = 0; /* Initialised ? */
+static int g_deb_init = 0; /* Debug output Initialised ? */
extern a1log default_log;
extern a1log *g_log;
@@ -247,9 +248,11 @@ typedef struct {
BYTE wReserved;
} osversioninfoexw;
-#define VER_NT_DOMAIN_CONTROLLER 0x0000002
-#define VER_NT_SERVER 0x0000003
-#define VER_NT_WORKSTATION 0x0000001
+#ifndef VER_NT_DOMAIN_CONTROLLER
+# define VER_NT_DOMAIN_CONTROLLER 0x0000002
+# define VER_NT_SERVER 0x0000003
+# define VER_NT_WORKSTATION 0x0000001
+#endif
static char *get_sys_info() {
static char sysinfo[100] = { "Unknown" };
@@ -328,14 +331,17 @@ static char *get_sys_info() {
}
-# define A1LOG_LOCK(log) \
+# define A1LOG_LOCK(log, deb) \
if (g_log_init == 0) { \
InitializeCriticalSection(&log->lock); \
EnterCriticalSection(&log->lock); \
g_log_init = 1; \
- va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
} else { \
EnterCriticalSection(&log->lock); \
+ } \
+ if (deb && !g_deb_init) { \
+ va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
+ g_deb_init = 1; \
}
# define A1LOG_UNLOCK(log) LeaveCriticalSection(&log->lock)
#endif
@@ -350,14 +356,17 @@ static char *get_sys_info() {
return sysinfo;
}
-# define A1LOG_LOCK(log) \
+# define A1LOG_LOCK(log, deb) \
if (g_log_init == 0) { \
pthread_mutex_init(&log->lock, NULL); \
pthread_mutex_lock(&log->lock); \
g_log_init = 1; \
- va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
} else { \
pthread_mutex_lock(&log->lock); \
+ } \
+ if (deb && !g_deb_init) { \
+ va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
+ g_deb_init = 1; \
}
# define A1LOG_UNLOCK(log) pthread_mutex_unlock(&log->lock)
#endif
@@ -485,7 +494,7 @@ void a1logv(a1log *log, int level, char *fmt, ...) {
if (log->verb >= level) {
va_list args;
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->logv(log->cntx, log, fmt, args);
va_end(args);
@@ -500,7 +509,7 @@ void a1logd(a1log *log, int level, char *fmt, ...) {
if (log->debug >= level) {
va_list args;
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 1);
va_start(args, fmt);
log->loge(log->cntx, log, fmt, args);
va_end(args);
@@ -515,20 +524,20 @@ void a1logw(a1log *log, char *fmt, ...) {
va_list args;
/* log to all the outputs, but only log once */
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->loge(log->cntx, log, fmt, args);
va_end(args);
A1LOG_UNLOCK(log);
if (log->logd != log->loge) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 1);
va_start(args, fmt);
log->logd(log->cntx, log, fmt, args);
va_end(args);
A1LOG_UNLOCK(log);
}
if (log->logv != log->loge && log->logv != log->logd) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->logv(log->cntx, log, fmt, args);
va_end(args);
@@ -545,7 +554,7 @@ void a1loge(a1log *log, int ecode, char *fmt, ...) {
va_list args;
if (log->errc == 0) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
log->errc = ecode;
va_start(args, fmt);
vsnprintf(log->errm, A1_LOG_BUFSIZE, fmt, args);
@@ -554,20 +563,20 @@ void a1loge(a1log *log, int ecode, char *fmt, ...) {
}
va_start(args, fmt);
/* log to all the outputs, but only log once */
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->loge(log->cntx, log, fmt, args);
va_end(args);
A1LOG_UNLOCK(log);
if (log->logd != log->loge) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 1);
va_start(args, fmt);
log->logd(log->cntx, log, fmt, args);
va_end(args);
A1LOG_UNLOCK(log);
}
if (log->logv != log->loge && log->logv != log->logd) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->logv(log->cntx, log, fmt, args);
va_end(args);
@@ -640,7 +649,7 @@ verbose(int level, char *fmt, ...) {
if (g_log->verb >= level) {
va_list args;
- A1LOG_LOCK(g_log);
+ A1LOG_LOCK(g_log, 0);
g_logv("%s: ",g_log->tag);
va_start(args, fmt);
g_log->logv(g_log->cntx, g_log, fmt, args);
@@ -654,7 +663,7 @@ void
warning(char *fmt, ...) {
va_list args;
- A1LOG_LOCK(g_log);
+ A1LOG_LOCK(g_log, 0);
g_loge("%s: Warning - ",g_log->tag);
va_start(args, fmt);
g_log->loge(g_log->cntx, g_log, fmt, args);
@@ -667,7 +676,7 @@ ATTRIBUTE_NORETURN void
error(char *fmt, ...) {
va_list args;
- A1LOG_LOCK(g_log);
+ A1LOG_LOCK(g_log, 0);
g_loge("%s: Error - ",g_log->tag);
va_start(args, fmt);
g_log->loge(g_log->cntx, g_log, fmt, args);
@@ -789,7 +798,7 @@ void osx_userinitiated_start() {
Class pic; /* Process info class */
SEL pis; /* Process info selector */
SEL bawo; /* Begin Activity With Options selector */
- id pi; /* Process info */
+ id pi; /* Process info */
id str;
if (osx_userinitiated_cnt++ != 0)
@@ -797,7 +806,8 @@ void osx_userinitiated_start() {
a1logd(g_log, 7, "OS X - User Initiated Activity start\n");
- /* We have to be conservative to avoid triggering an exception when run on older OS X */
+ /* We have to be conservative to avoid triggering an exception when run on older OS X, */
+ /* since beginActivityWithOptions is only available in >= 10.9 */
if ((pic = (Class)objc_getClass("NSProcessInfo")) == nil) {
return;
}
@@ -2200,3 +2210,255 @@ void write_INR64_le(ORD8 *p, INR64 d) {
p[7] = (ORD8)(d >> 56);
}
+/*******************************/
+/* System independent timing */
+
+#ifdef NT
+
+/* Sleep for the given number of msec */
+void msec_sleep(unsigned int msec) {
+ Sleep(msec);
+}
+
+/* Return the current time in msec since */
+/* the first invokation of msec_time() */
+/* (Is this based on timeGetTime() ? ) */
+unsigned int msec_time() {
+ unsigned int rv;
+ static unsigned int startup = 0;
+
+ rv = GetTickCount();
+ if (startup == 0)
+ startup = rv;
+
+ return rv - startup;
+}
+
+/* Return the current time in usec */
+/* since the first invokation of usec_time() */
+/* Return -1.0 if not available */
+double usec_time() {
+ double rv;
+ LARGE_INTEGER val;
+ static double scale = 0.0;
+ static LARGE_INTEGER startup;
+
+ if (scale == 0.0) {
+ if (QueryPerformanceFrequency(&val) == 0)
+ return -1.0;
+ scale = 1000000.0/val.QuadPart;
+ QueryPerformanceCounter(&val);
+ startup.QuadPart = val.QuadPart;
+
+ } else {
+ QueryPerformanceCounter(&val);
+ }
+ val.QuadPart -= startup.QuadPart;
+
+ rv = val.QuadPart * scale;
+
+ return rv;
+}
+
+#endif /* NT */
+
+#if defined(UNIX)
+
+/* Sleep for the given number of msec */
+/* (Note that OS X 10.9+ App Nap can wreck this, unless */
+/* it is turned off.) */
+void msec_sleep(unsigned int msec) {
+#ifdef NEVER
+ if (msec > 1000) {
+ unsigned int secs;
+ secs = msec / 1000;
+ msec = msec % 1000;
+ sleep(secs);
+ }
+ usleep(msec * 1000);
+#else
+ struct timespec ts;
+
+ ts.tv_sec = msec / 1000;
+ ts.tv_nsec = (msec % 1000) * 1000000;
+ nanosleep(&ts, NULL);
+#endif
+}
+
+
+#if defined(__APPLE__) && !defined(CLOCK_MONOTONIC)
+
+#include <mach/mach_time.h>
+
+unsigned int msec_time() {
+ mach_timebase_info_data_t timebase;
+ static uint64_t startup = 0;
+ uint64_t time;
+ double msec;
+
+ time = mach_absolute_time();
+ if (startup == 0)
+ startup = time;
+
+ mach_timebase_info(&timebase);
+ time -= startup;
+ msec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e6);
+
+ return (unsigned int)floor(msec + 0.5);
+}
+
+/* Return the current time in usec */
+/* since the first invokation of usec_time() */
+double usec_time() {
+ mach_timebase_info_data_t timebase;
+ static uint64_t startup = 0;
+ uint64_t time;
+ double usec;
+
+ time = mach_absolute_time();
+ if (startup == 0)
+ startup = time;
+
+ mach_timebase_info(&timebase);
+ time -= startup;
+ usec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e3);
+
+ return usec;
+}
+
+#else
+
+/* Return the current time in msec */
+/* since the first invokation of msec_time() */
+unsigned int msec_time() {
+ unsigned int rv;
+ static struct timespec startup = { 0, 0 };
+ struct timespec cv;
+
+ clock_gettime(CLOCK_MONOTONIC, &cv);
+
+ /* Set time to 0 on first invocation */
+ if (startup.tv_sec == 0 && startup.tv_nsec == 0)
+ startup = cv;
+
+ /* Subtract, taking care of carry */
+ cv.tv_sec -= startup.tv_sec;
+ if (startup.tv_nsec > cv.tv_nsec) {
+ cv.tv_sec--;
+ cv.tv_nsec += 1000000000;
+ }
+ cv.tv_nsec -= startup.tv_nsec;
+
+ /* Convert nsec to msec */
+ rv = cv.tv_sec * 1000 + cv.tv_nsec / 1000000;
+
+ return rv;
+}
+
+/* Return the current time in usec */
+/* since the first invokation of usec_time() */
+double usec_time() {
+ double rv;
+ static struct timespec startup = { 0, 0 };
+ struct timespec cv;
+
+ clock_gettime(CLOCK_MONOTONIC, &cv);
+
+ /* Set time to 0 on first invocation */
+ if (startup.tv_sec == 0 && startup.tv_nsec == 0)
+ startup = cv;
+
+ /* Subtract, taking care of carry */
+ cv.tv_sec -= startup.tv_sec;
+ if (startup.tv_nsec > cv.tv_nsec) {
+ cv.tv_sec--;
+ cv.tv_nsec += 1000000000;
+ }
+ cv.tv_nsec -= startup.tv_nsec;
+
+ /* Convert to usec */
+ rv = cv.tv_sec * 1000000.0 + cv.tv_nsec/1000;
+
+ return rv;
+}
+
+#endif
+
+#endif /* UNIX */
+
+/*******************************/
+/* Debug convenience functions */
+/*******************************/
+
+#define DEB_MAX_CHAN 15
+
+/* Print an int vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPiv(int di, int *p) {
+ static char buf[5][DEB_MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > DEB_MAX_CHAN)
+ di = DEB_MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%d", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print a double color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPdv(int di, double *p) {
+ static char buf[5][DEB_MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > DEB_MAX_CHAN)
+ di = DEB_MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%.8f", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print a float color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPfv(int di, float *p) {
+ static char buf[5][DEB_MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > DEB_MAX_CHAN)
+ di = DEB_MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%.8f", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+#undef DEB_MAX_CHAN
diff --git a/numlib/numsup.h b/numlib/numsup.h
index 366763d..9d55daf 100644
--- a/numlib/numsup.h
+++ b/numlib/numsup.h
@@ -43,9 +43,9 @@
/* so long shouldn't really be used in any code.... */
/* (duplicated in icc.h) */
-/* Use __LP64__ as cross platform 64 bit pointer #define */
-#if !defined(__LP64__) && defined(_WIN64)
-# define __LP64__ 1
+/* Use __P64__ as cross platform 64 bit pointer #define */
+#if defined(__LP64__) || defined(__ILP64__) || defined(__LLP64__) || defined(_WIN64)
+# define __P64__ 1
#endif
#ifndef ORD32
@@ -59,17 +59,25 @@
#define INR8 int8_t /* 8 bit signed */
#define INR16 int16_t /* 16 bit signed */
#define INR32 int32_t /* 32 bit signed */
-#define INR64 int64_t /* 64 bit signed - not used in icclib */
+#define INR64 int64_t /* 64 bit signed */
#define ORD8 uint8_t /* 8 bit unsigned */
#define ORD16 uint16_t /* 16 bit unsigned */
#define ORD32 uint32_t /* 32 bit unsigned */
-#define ORD64 uint64_t /* 64 bit unsigned - not used in icclib */
+#define ORD64 uint64_t /* 64 bit unsigned */
#define PNTR intptr_t
#define PF64PREC "ll" /* printf format precision specifier */
#define CF64PREC "LL" /* Constant precision specifier */
+#ifndef ATTRIBUTE_NORETURN
+# ifdef _MSC_VER
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+# else
+# define ATTRIBUTE_NORETURN __attribute__((noreturn))
+# endif
+#endif
+
#else /* !__STDC_VERSION__ */
#ifdef _MSC_VER
@@ -77,17 +85,21 @@
#define INR8 __int8 /* 8 bit signed */
#define INR16 __int16 /* 16 bit signed */
#define INR32 __int32 /* 32 bit signed */
-#define INR64 __int64 /* 64 bit signed - not used in icclib */
+#define INR64 __int64 /* 64 bit signed */
#define ORD8 unsigned __int8 /* 8 bit unsigned */
#define ORD16 unsigned __int16 /* 16 bit unsigned */
#define ORD32 unsigned __int32 /* 32 bit unsigned */
-#define ORD64 unsigned __int64 /* 64 bit unsigned - not used in icclib */
+#define ORD64 unsigned __int64 /* 64 bit unsigned */
#define PNTR UINT_PTR
#define PF64PREC "I64" /* printf format precision specifier */
#define CF64PREC "LL" /* Constant precision specifier */
+#ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+#endif
+
#else /* !_MSC_VER */
/* The following works on a lot of modern systems, including */
@@ -101,29 +113,28 @@
#define ORD32 unsigned int /* 32 bit unsigned */
#ifdef __GNUC__
-# define INR64 long long /* 64 bit signed - not used in icclib */
-# define ORD64 unsigned long long /* 64 bit unsigned - not used in icclib */
-# define PF64PREC "ll" /* printf format precision specifier */
-# define CF64PREC "LL" /* Constant precision specifier */
+# ifdef __LP64__ /* long long could be 128 bit ? */
+# define INR64 long /* 64 bit signed */
+# define ORD64 unsigned long /* 64 bit unsigned */
+# define PF64PREC "l" /* printf format precision specifier */
+# define CF64PREC "L" /* Constant precision specifier */
+# else
+# define INR64 long long /* 64 bit signed */
+# define ORD64 unsigned long long /* 64 bit unsigned */
+# define PF64PREC "ll" /* printf format precision specifier */
+# define CF64PREC "LL" /* Constant precision specifier */
+# endif /* !__LP64__ */
#endif /* __GNUC__ */
#define PNTR unsigned long
-#endif /* !_MSC_VER */
-#endif /* !__STDC_VERSION__ */
-#endif /* !ORD32 */
-
-#ifdef _MSC_VER
-#ifndef ATTRIBUTE_NORETURN
-# define ATTRIBUTE_NORETURN __declspec(noreturn)
-#endif
-#endif
-
-#ifdef __GNUC__
#ifndef ATTRIBUTE_NORETURN
# define ATTRIBUTE_NORETURN __attribute__((noreturn))
#endif
-#endif
+
+#endif /* !_MSC_VER */
+#endif /* !__STDC_VERSION__ */
+#endif /* !ORD32 */
/* =========================================================== */
/* System compatibility #defines */
@@ -517,6 +528,34 @@ void write_INR64_be(ORD8 *p, INR64 d);
void write_INR64_le(ORD8 *p, INR64 d);
/*******************************************/
+
+/* Sleep for the given number of msec */
+void msec_sleep(unsigned int msec);
+
+/* Return the current time in msec since */
+/* the first invokation of msec_time() */
+unsigned int msec_time();
+
+/* Return the current time in usec */
+/* (The first invokation of usec_time() returns zero) */
+double usec_time();
+
+/*******************************************/
+/* Debug convenience functions (duplicated in icc) */
+
+/* Print an int vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPiv(int di, int *p);
+
+/* Print a double color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPdv(int di, double *p);
+
+/* Print a float color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPfv(int di, float *p);
+
+/*******************************************/
/* Numerical diagnostics */
#ifndef isNan
diff --git a/numlib/ui.c b/numlib/ui.c
index a3cdbe8..390a332 100644
--- a/numlib/ui.c
+++ b/numlib/ui.c
@@ -32,6 +32,8 @@
main thread, spawn a secondary thread to run the
application main(), and then do nothing but
service the events in the main thread.
+ We can also pass functions back to be run in the main thread,
+ and wait for events in the main thread to be processed.
Note though that Cocoa has poor thread safety :-
ie. NSRunLoop can't be used to access events - use CFRunLoop
@@ -45,6 +47,7 @@
# include <stdio.h>
# include <stdlib.h>
# include <pthread.h>
+# include "ui.h"
# include <Foundation/Foundation.h>
# include <AppKit/AppKit.h>
@@ -66,6 +69,10 @@ static char **g_argv;
pthread_t ui_thid = 0; /* Thread ID of main thread running io run loop */
pthread_t ui_main_thid = 0; /* Thread ID of thread running application main() */
+static pthread_mutex_t ui_lock1, ui_lock2; /* Protect wait code */
+static pthread_cond_t ui_cond1, ui_cond2; /* Signal to waiting thread */
+static int ui_event1 = 0, ui_event2 = 0; /* Sync event was received */
+
extern int uimain(int argc, char *argv[]);
/* Thread that calls the real application main() */
@@ -79,12 +86,21 @@ static void *callMain(void *p) {
/* Turn App Nap off */
osx_userinitiated_start();
+ /* Should we catch and report exceptions ? */
+
rv = uimain(g_argc, g_argv);
+ /* Restore App Nap state */
osx_userinitiated_end();
[tpool release];
+ /* Cleanup, since main thread won't return */
+ pthread_cond_destroy(&ui_cond1);
+ pthread_cond_destroy(&ui_cond2);
+ pthread_mutex_destroy(&ui_lock1);
+ pthread_mutex_destroy(&ui_lock2);
+
exit(rv);
}
@@ -101,37 +117,24 @@ static void *callMain(void *p) {
int main(int argc, char ** argv) {
+ pthread_mutex_init(&ui_lock1, NULL);
+ pthread_mutex_init(&ui_lock2, NULL);
+ pthread_cond_init(&ui_cond1, NULL);
+ pthread_cond_init(&ui_cond2, NULL);
+
ui_thid = pthread_self();
/* Create an NSApp */
static NSAutoreleasePool *pool = nil;
- ProcessSerialNumber psn = { 0, 0 };
-
- /* Transform the process so that the desktop interacts with it properly. */
- /* We don't need resources or a bundle if we do this. */
- if (GetCurrentProcess(&psn) == noErr) {
- OSStatus stat;
- if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn,
- kProcessTransformToForegroundApplication)) != noErr) {
-// fprintf(stderr,"TransformProcess failed with code %d\n",stat);
- } else {
-// fprintf(stderr,"TransformProcess suceeded\n");
- }
-// if ((stat = SetFrontProcess(&psn)) != noErr) {
-// fprintf(stderr,"SetFrontProcess returned error %d\n",stat);
-// }
- }
pool = [NSAutoreleasePool new];
[NSApplication sharedApplication]; /* Creates NSApp */
- [NSApp finishLaunching];
- /* We seem to need this, because otherwise we don't get focus automatically */
- [NSApp activateIgnoringOtherApps: YES];
+ [NSApp finishLaunching];
/* We need to create at least one NSThread to tell Cocoa that we are using */
- /* threads, and to protect Cococa objects. */
+ /* threads, and to protect Cococa objects. (We don't actually have to start the thread.) */
[NSThread detachNewThreadSelector:@selector(dummyfunc:) toTarget:[MainClass class] withObject:nil];
/* Call the real main() in another thread */
@@ -156,13 +159,163 @@ int main(int argc, char ** argv) {
}
/* Service the run queue */
- [NSApp run];
+ {
+ NSEvent *event;
+ NSDate *to;
+
+ /* Process events, looking for application events. */
+ for (;;) {
+ /* Hmm. Assume to is autorelease */
+ to = [NSDate dateWithTimeIntervalSinceNow:1.0];
+ /* Hmm. Assume event is autorelease */
+ if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:to inMode:NSDefaultRunLoopMode dequeue:YES]) != nil) {
+
+ /* call function message */
+ if ([event type] == NSApplicationDefined
+ && [event subtype] == 1) {
+ void *cntx = (void *)[event data1];
+ void (*function)(void *cntx) = (void (*)(void *)) [event data2];
+
+ function(cntx);
+
+ pthread_mutex_lock(&ui_lock1);
+ ui_event1 = 1;
+ pthread_cond_signal(&ui_cond1);
+ pthread_mutex_unlock(&ui_lock1);
+ [event release];
+
+ /* event flush message */
+ } else if ([event type] == NSApplicationDefined
+ && [event subtype] == 2) {
+ pthread_mutex_lock(&ui_lock2);
+ ui_event2 = 1;
+ pthread_cond_signal(&ui_cond2);
+ pthread_mutex_unlock(&ui_lock2);
+ [event release];
+
+ /* Everything else */
+ } else {
+ [NSApp sendEvent:event];
+ }
+ }
+ }
+ }
/* Note that we don't actually clean this up on exit - */
/* possibly we can't. */
// [NSApp terminate: nil];
}
+/* Call this if we decide we are actually going to display something in the GUI. */
+/* We switch to "interact with the Dock" mode. */
+void ui_UsingGUI() {
+ static int attached = 0;
+ ProcessSerialNumber psn = { 0, 0 };
+
+ if (!attached) {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ /* Make the application appear in the Dock, and interact with the desktop properly. */
+ /* (Unbundled applications default to NSApplicationActivationPolicyProhibited) */
+ [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+
+#else
+# if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
+ /* Make the application appear in the Dock, and interact with the desktop properly. */
+ /* We don't need resources or a bundle if we do this. */
+ if (GetCurrentProcess(&psn) == noErr) {
+ OSStatus stat;
+ if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn,
+ kProcessTransformToForegroundApplication)) != noErr) {
+ fprintf(stderr,"TransformProcess failed with code %d\n",stat);
+
+ /* An older trick uses an undocumented API:
+ CPSEnableForegroundOperation(&processSerialNum, 0, 0, 0, 0);
+ */
+ } else {
+ // fprintf(stderr,"TransformProcess suceeded\n");
+ }
+ }
+# endif /* OS X 10.3 */
+#endif /* !OS X 10.6 */
+
+ /* We seem to need this, because otherwise we don't get focus automatically */
+ [NSApp activateIgnoringOtherApps: YES];
+
+ attached = 1;
+ }
+}
+
+/* Run a function in the main thread and return when it is complete. */
+/* (It's up to the function to record it's result status in its context) */
+void ui_runInMainThreadAndWait(void *cntx, void (*function)(void *cntx)) {
+
+ NSEvent *event;
+ NSPoint point = { 0.0, 0.0 };
+ int rv;
+
+ pthread_mutex_lock(&ui_lock1);
+ ui_event1 = 0;
+
+ event = [NSEvent otherEventWithType:NSApplicationDefined
+ location:point
+ modifierFlags:0
+ timestamp:0.0
+ windowNumber:0
+ context:nil
+ subtype:1
+ data1:(long)cntx /* long same size as * */
+ data2:(long)function];
+ [NSApp postEvent:event atStart:NO];
+
+ // unlock and wait for signal
+ for (;;) { /* Ignore spurious wakeups */
+ if ((rv = pthread_cond_wait(&ui_cond1, &ui_lock1)) != 0) {
+ break; // Hmm.
+ }
+ if (ui_event1) /* Got what we were waiting for */
+ break;
+ }
+ pthread_mutex_unlock(&ui_lock1);
+}
+
+
+/* We are about to change the UI */
+void ui_aboutToWait() {
+
+ pthread_mutex_lock(&ui_lock2);
+ ui_event2 = 0;
+}
+
+/* Wait until we are sure our UI change is complete, */
+/* because our event has trickled through. */
+void ui_waitForEvents() {
+ NSEvent *event;
+ NSPoint point = { 0.0, 0.0 };
+ int rv;
+
+ event = [NSEvent otherEventWithType:NSApplicationDefined
+ location:point
+ modifierFlags:0
+ timestamp:0.0
+ windowNumber:0
+ context:nil
+ subtype:2
+ data1:0
+ data2:0];
+ [NSApp postEvent:event atStart:NO];
+
+ // unlock and wait for signal
+ for (;;) { /* Ignore spurious wakeups */
+ if ((rv = pthread_cond_wait(&ui_cond2, &ui_lock2)) != 0) {
+ break; // Hmm.
+ }
+ if (ui_event2) /* Got what we were waiting for */
+ break;
+ }
+ pthread_mutex_unlock(&ui_lock2);
+}
+
#else /* !APPLE */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -171,6 +324,11 @@ int main(int argc, char ** argv) {
/* This is a mechanism to force libui to link */
int ui_initialized = 1; /* Nothing needs initializing */
+/* Call this if we decide we are actually going to display */
+/* something in the GUI */
+void ui_UsingGUI() {
+}
+
#endif /* !APPLE */
#endif /* UNIX */
@@ -262,4 +420,9 @@ int ui_initialized = 1; /* Nothing needs initializing */
#endif /* !NEVER */
+/* Call this if we decide we are actually going to display */
+/* something in the GUI */
+void ui_UsingGUI() {
+}
+
#endif /* NT */
diff --git a/numlib/ui.h b/numlib/ui.h
index e1d7a58..a282c26 100644
--- a/numlib/ui.h
+++ b/numlib/ui.h
@@ -21,12 +21,25 @@
extern int ui_initialized;
static int *pui_initialized = &ui_initialized;
+/* Call this if we decide we are actually going to display */
+/* something in the GUI */
+void ui_UsingGUI();
+
#ifdef UNIX
# ifdef __APPLE__
extern pthread_t ui_thid; /* Thread ID of main thread running io run loop */
extern pthread_t ui_main_thid; /* Thread ID of thread running application main() */
+/* Run a function in the main thread and return when it is complete */
+void ui_runInMainThreadAndWait(void *cntx, void (*function)(void *context));
+
+/* We are about to change the UI */
+void ui_aboutToWait();
+
+/* Wait until we are sure our UI change is complete */
+void ui_waitForEvents();
+
#ifndef __UI_C__
# define main uimain
#endif
diff --git a/plot/plot.c b/plot/plot.c
index e3cd5bf..d7b4799 100644
--- a/plot/plot.c
+++ b/plot/plot.c
@@ -120,7 +120,7 @@ static plot_info pd;
static int do_plot_imp(
int flags,
double xmin, double xmax, double ymin, double ymax, /* Bounding box */
- double ratio, /* Aspect ratio of window, X/Y */
+ double ratio, /* Aspect ratio of window, X/Y, 1.0 = nominal */
int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
double *x1, double *x2,
double *yy[MXGPHS], char **ntext,
@@ -369,7 +369,7 @@ int n) { /* Number of values */
xmin = ymin = 1e6;
xmax = ymax = -1e6;
- for (i = 0; i < n; i++) {
+ for (i = 0; i < nn; i++) {
if (xmin > x[i])
xmin = x[i];
if (xmax < x[i])
@@ -433,7 +433,7 @@ int m) {
xmin = ymin = 1e6;
xmax = ymax = -1e6;
- for (i = 0; i < n; i++) {
+ for (i = 0; i < nn; i++) {
if (xmin > x[i])
xmin = x[i];
if (xmax < x[i])
@@ -892,6 +892,8 @@ static int do_plot_imp(
/* ------------------------------------------- */
/* Setup windows stuff */
{
+ ui_UsingGUI();
+
/* It would be nice to reduce number of globals. */
/* We don't clean up properly either - ie. don't delete thread etc. */
@@ -908,11 +910,14 @@ static int do_plot_imp(
}
while (plot_hwnd == NULL)
Sleep(50);
+
+ SetForegroundWindow(plot_hwnd); /* Raise */
}
plot_signal = 0;
- SetForegroundWindow(plot_hwnd);
+ if (dowait > 0)
+ SetForegroundWindow(plot_hwnd); /* Raise */
/* Force a repaint with the new data */
if (!InvalidateRgn(plot_hwnd,NULL,TRUE)) {
@@ -1321,6 +1326,14 @@ static void DoPlot(NSRect *rect, plot_info *pdp);
@end
+/* Function called back by main thread to trigger a drawRect */
+
+static void doSetNeedsDisplay(void *cntx) {
+ cntx_t *cx = (cntx_t *)cntx;
+
+ [cx->view setNeedsDisplay: YES ];
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - -
@interface PLWin : NSWindow {
@@ -1362,7 +1375,8 @@ static void DoPlot(NSRect *rect, plot_info *pdp);
@end
/* Create our window */
-static void create_my_win(cntx_t *cx) {
+static void create_my_win(void *cntx) {
+ cntx_t *cx = (cntx_t *)cntx;
NSRect wRect;
/* Create Window */
@@ -1491,6 +1505,8 @@ static int do_plot_imp(
pd.o = abs(o);
}
+ ui_UsingGUI();
+
/* If we may be in a different thread to the main thread or */
/* the application thread, establish our own pool. */
NSAutoreleasePool *tpool = nil;
@@ -1511,10 +1527,26 @@ static int do_plot_imp(
if ((plot_cx = (cntx_t *)calloc(sizeof(cntx_t), 1)) == NULL)
error("new_dispwin: Malloc failed (cntx_t)\n");
- create_my_win(plot_cx);
+ /* Prepare to wait for events */
+ ui_aboutToWait();
+
+ /* Run the window creation in the main thread and wait for it */
+ ui_runInMainThreadAndWait((void *)plot_cx, create_my_win);
+
+ /* Wait for events generated by window creation to complete */
+ ui_waitForEvents();
} else { /* Trigger an update */
- [plot_cx->view setNeedsDisplay: YES ];
+// [plot_cx->view setNeedsDisplay: YES ];
+
+ /* Prepare to wait for events */
+ ui_aboutToWait();
+
+ /* Run the window creation in the main thread and wait for it */
+ ui_runInMainThreadAndWait((void *)plot_cx, doSetNeedsDisplay);
+
+ /* Wait for any events generated by paint to complete */
+ ui_waitForEvents();
}
/* (Main thread will service events) */
@@ -1960,6 +1992,8 @@ static int do_plot_imp(
unsigned long myforeground,mybackground;
int done;
+ ui_UsingGUI();
+
/* open the display */
if (mydisplay == NULL) {
mydisplay = XOpenDisplay("");
@@ -2013,8 +2047,10 @@ static int do_plot_imp(
XSendEvent(mydisplay, mywindow, False, ExposureMask, (XEvent *)&ev);
} else {
- XMapRaised(mydisplay,mywindow);
- debugf(("Raised window\n"));
+ if (pd.dowait > 0) {
+ XMapRaised(mydisplay,mywindow);
+ debugf(("Raised window\n"));
+ }
}
/* Main event loop */
diff --git a/plot/plot.h b/plot/plot.h
index 89bf16b..b7d06f7 100644
--- a/plot/plot.h
+++ b/plot/plot.h
@@ -71,7 +71,7 @@ int do_plot10p(double *x, double *y1, double *y2, double *y3, double *y4, double
/* Plot a bunch of vectors + points + optional colored points & notation */
/* return 0 on success, -1 on error */
-/* Vectors are x1, y1 to x2, y2 with 'X' at x2, y3, */
+/* Vectors are x1, y1 to x2, y2 with 'X' at x2, y2, */
/* Colored annotated Crosss at x3, y3. */
int do_plot_vec(double xmin, double xmax, double ymin, double ymax,
double *x1, double *y1, double *x2, double *y2, int n,
@@ -81,7 +81,7 @@ int do_plot_vec(double xmin, double xmax, double ymin, double ymax,
/* Plot a bunch of vectors + points + optional colored points & notation */
/* + optional colored vectors */
/* return 0 on success, -1 on error */
-/* Vectors are x1, y1 to x2, y2 with annotated 'X' at x2, y3, */
+/* Vectors are x1, y1 to x2, y2 with annotated 'X' at x2, y2, */
/* Colored annotated Crosss at x3, y3. */
/* Colored vector from x4, y4 to x5, y5 */
int do_plot_vec2(double xmin, double xmax, double ymin, double ymax,
diff --git a/plot/vrml.c b/plot/vrml.c
index 0121c53..d56e62d 100644
--- a/plot/vrml.c
+++ b/plot/vrml.c
@@ -600,7 +600,9 @@ double cc[3] /* Surface color, cc == NULL or cc[0] < 0.0 */
if (set < 0 || set > 9)
error("vrml make_line_tri_quad set %d out of range",set);
- if (s->set[set].npoints > 0 && s->set[set].tqary[0].ix[2] < 0) /* First is a line */
+ if (s->set[set].npoints > 0
+ && s->set[set].ntrqu > 0
+ && s->set[set].tqary[0].ix[2] < 0) /* First is a line */
lines = 1; /* Assume all are lines */
if (cc != NULL && cc[0] >= 0.0) {
@@ -1745,7 +1747,6 @@ static int do_flush(vrml *s) {
fflush(s->fp);
rv = fclose(s->fp);
-
/* Check that there are the x3dom files with the output file */
if (s->fmt == fmt_x3dom) {
char *xl, *x3name;
diff --git a/plot/vrml.h b/plot/vrml.h
index ff44a6c..d3c86c3 100644
--- a/plot/vrml.h
+++ b/plot/vrml.h
@@ -225,10 +225,10 @@ char *vrml_format();
/* Create a vrml/x3d plot object. */
/* Filename will have appropriate extension added automatically. */
-vrml *new_vrml_vdist(char *name, int doaxes, vrml_space ispace, double vdist);
+vrml *new_vrml(char *name, int doaxes, vrml_space ispace);
/* Same as above but override default Z viewing distance */
-vrml *new_vrml(char *name, int doaxes, vrml_space ispace);
+vrml *new_vrml_vdist(char *name, int doaxes, vrml_space ispace, double vdist);
#define VRML_H
diff --git a/profile/applycal.c b/profile/applycal.c
index 17187db..ff9a76d 100644
--- a/profile/applycal.c
+++ b/profile/applycal.c
@@ -33,7 +33,6 @@
#include "numlib.h"
#include "rspl.h"
#include "xicc.h"
-#include "ui.h"
#undef DEBUG
diff --git a/profile/colprof.c b/profile/colprof.c
index 7309dc4..b359ebb 100644
--- a/profile/colprof.c
+++ b/profile/colprof.c
@@ -49,6 +49,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
+#include <ctype.h>
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
@@ -135,8 +136,10 @@ void usage(char *diag, ...) {
/* Research options: */
/* fprintf(stderr," -r sSMOOTH RSPL or shaper suplimental optimised smoothing factor\n"); */
/* fprintf(stderr," -r rSMOOTH RSPL or shaper raw underlying smoothing factor\n"); */
- fprintf(stderr," -s src%s Apply gamut mapping to output profile perceptual B2A table for given source space\n",ICC_FILE_EXT);
- fprintf(stderr," -S src%s Apply gamut mapping to output profile perceptual and saturation B2A table\n",ICC_FILE_EXT);
+ fprintf(stderr," -s src%s|cperc Apply gamut mapping to output profile perceptual B2A table\n",ICC_FILE_EXT);
+ fprintf(stderr," for given source space, or compression percentage\n");
+ fprintf(stderr," -S src%s|experc Apply gamut mapping to output profile perceptual and\n",ICC_FILE_EXT);
+ fprintf(stderr," and saturation B2A table, or expansion percentage\n");
fprintf(stderr," -nP Use colormetric source gamut to make output profile perceptual table\n");
fprintf(stderr," -nS Use colormetric source gamut to make output profile saturation table\n");
fprintf(stderr," -g src.gam Use source image gamut as well for output profile gamut mapping\n");
@@ -207,6 +210,7 @@ int main(int argc, char *argv[]) {
icxIllumeType illum = icxIT_none; /* Spectral illuminant (defaults to D50) */
xspect cust_illum; /* Custom illumination spectrum */
icxObserverType observ = icxOT_none; /* Observer (defaults to 1931 2 degree) */
+ int gcompr = 0, gexpr = 0; /* Gamut compression/expansion % instead of Input icc profile */
char ipname[MAXNAMEL+1] = ""; /* Input icc profile - enables gamut map */
char sgname[MAXNAMEL+1] = ""; /* Image source gamut name */
char absstring[3 * MAXNAMEL +1]; /* Storage for absnames */
@@ -640,14 +644,24 @@ int main(int argc, char *argv[]) {
} else if (strcmp(na, "F10") == 0) {
tillum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
tillum = icxIT_custom;
- if (read_xspect(&cust_tillum, na) != 0)
+ if (read_xspect(&cust_tillum, &mt, na) != 0)
usage("Failed to read custom target illuminant spectrum in file '%s'",na);
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("Target illuminant '%s' is wrong measurement type",na);
+ }
}
}
}
- /* Spectral Illuminant type */
+ /* CIE Illuminant type */
else if (argv[fa][1] == 'i') {
if (na == NULL) usage("Expect argument to illuminant flag -i");
fa = nfa;
@@ -676,10 +690,20 @@ int main(int argc, char *argv[]) {
spec = 1;
illum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
spec = 1;
illum = icxIT_custom;
- if (read_xspect(&cust_illum, na) != 0)
+ if (read_xspect(&cust_illum, &mt, na) != 0)
usage("Failed to read custom illuminant spectrum in file '%s'",na);
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("CIE illuminant '%s' is wrong measurement type",na);
+ }
}
}
@@ -727,15 +751,51 @@ int main(int argc, char *argv[]) {
}
}
+ /* Percetual Source Compression and Perceptual/Saturation Gamut Maping mode enable */
/* Percetual Source Gamut and Perceptual/Saturation Gamut Maping mode enable */
else if (argv[fa][1] == 's'
|| argv[fa][1] == 'S') {
- if (argv[fa][1] == 'S')
+ int sat = 0;
+ if (argv[fa][1] == 'S') {
sepsat = 1;
+ sat = 1;
+ } else {
+ sepsat = 0;
+ }
if (na == NULL)
usage("Unrecognised argument to source gamut flag -%c",argv[fa][1]);
fa = nfa;
- strncpy(ipname,na,MAXNAMEL); ipname[MAXNAMEL] = '\000';
+ {
+ char *cp;
+ int comp = 0;
+ for (cp = na; *cp != '\000'; cp++) {
+ if (!isdigit(*cp))
+ break;
+ }
+ /* If general gamut compression/expansion mode */
+ if (*cp == '\000') {
+ int ratio = atoi(na);
+ if (ratio <= 0 || ratio > 100) {
+ usage("Gamut -%c %s %d%% must be > 0 and < 100",
+ argv[fa][1], sat ? "expansion" : "compression", ratio);
+ }
+ if (sat) {
+ gexpr = ratio;
+ if (gcompr == 0)
+ gcompr = ratio;
+ } else {
+ gcompr = ratio;
+ if (gexpr == 0)
+ gexpr = ratio;
+ }
+ }
+ }
+ /* Not compression %, so assume it's a filename. */
+ /* We allow both filename and general compression to allow */
+ /* for a non-default L mapping. */
+ if (gcompr == 0) {
+ strncpy(ipname,na,MAXNAMEL); ipname[MAXNAMEL] = '\000';
+ }
}
/* Source image gamut */
@@ -899,10 +959,10 @@ int main(int argc, char *argv[]) {
if (fwacomp && spec == 0)
error("FWA compensation only works when viewer and/or illuminant selected");
- if (pgmi_set && ipname[0] == '\000')
+ if (pgmi_set && (ipname[0] == '\000' && gcompr == 0))
warning("-t perceptual intent override only works if -s srcprof or -S srcprof is used");
- if (sgmi_set && ipname[0] == '\000')
+ if (sgmi_set && (ipname[0] == '\000' && gcompr == 0))
warning("-T saturation intent override only works if -S srcprof is used");
if (sgmi_set && sepsat == 0) { /* Won't do much otherwise */
@@ -911,12 +971,14 @@ int main(int argc, char *argv[]) {
sepsat = 1;
}
- if (gamdiag && ipname[0] == '\000')
- warning("no gamut mapping called for, so -P will produce nothing");
+ if (gamdiag && (ipname[0] == '\000' && gcompr == 0))
+ warning("No gamut mapping called for, so -P will produce nothing");
if (sgname[0] != '\000' && ipname[0] == '\000')
warning("-g srcgam will do nothing without -s srcprof or -S srcprof");
+ /* Should warning input viewing condition set and ipname[0] == '\000' */
+
if (oquality == -1) { /* B2A tables will be used */
oquality = iquality;
}
@@ -945,7 +1007,7 @@ int main(int argc, char *argv[]) {
|| strcmp(icg->t[0].kdata[dti],"EMISINPUT") == 0) {
if (illum != icxIT_none)
warning("-i illuminant ignored for emissive reference type");
- if (fwacomp != icxIT_none)
+ if (fwacomp != 0)
warning("-f FWA compensation ignored for emissive reference type");
fwacomp = 0;
@@ -1023,7 +1085,7 @@ int main(int argc, char *argv[]) {
int kmax;
kmax = atoi(icg->t[0].kdata[ti]);
if (kmax > 0 && kmax <= 100.0) {
- if (klimit > 0 && klimit <= 100.0) { /* User has specified limit as option */
+ if (klimit >= 0 && klimit <= 100.0) { /* User has specified limit as option */
if (kmax < klimit) {
warning("Black ink limit greater than original chart! (%d%% > %d%%)",klimit,kmax);
}
@@ -1114,6 +1176,7 @@ int main(int argc, char *argv[]) {
&ink, inname, outname, icg,
spec, tillum, &cust_tillum, illum, &cust_illum, observ, fwacomp,
smooth, avgdev, 1.0,
+ gcompr, gexpr,
ipname[0] != '\000' ? ipname : NULL,
sgname[0] != '\000' ? sgname : NULL,
absnames,
@@ -1162,6 +1225,7 @@ int main(int argc, char *argv[]) {
NULL, inname, outname, icg,
spec, icxIT_none, NULL, illum, &cust_illum, observ, 0,
smooth, avgdev, demph,
+ gcompr, gexpr,
ipname[0] != '\000' ? ipname : NULL,
sgname[0] != '\000' ? sgname : NULL,
absnames,
diff --git a/profile/colverify.c b/profile/colverify.c
index 1ab3f64..86d5575 100644
--- a/profile/colverify.c
+++ b/profile/colverify.c
@@ -25,7 +25,7 @@
* they are just ignored.
*/
-#define DEBUG
+#undef DEBUG
#define verbo stdout
@@ -61,6 +61,7 @@ usage(void) {
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
fprintf(stderr,"usage: colverify [-options] target.ti3 measured.ti3\n");
fprintf(stderr," -v [n] Verbose mode, n >= 2 print each value\n");
+ fprintf(stderr," -l Match patches by sample location rather than id\n");
fprintf(stderr," -n Normalise each files reading to its white Y\n");
fprintf(stderr," -N Normalise each files reading to its white XYZ\n");
fprintf(stderr," -m Normalise each files reading to its white X+Y+Z\n");
@@ -83,6 +84,7 @@ usage(void) {
fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
fprintf(stderr," -L profile.%s Skip any first file out of profile gamut patches\n",ICC_FILE_EXT_ND);
fprintf(stderr," -X file.ccmx Apply Colorimeter Correction Matrix to second file\n");
+// fprintf(stderr," -Z A|X Just print Average|Max +tab\n");
fprintf(stderr," target.ti3 Target (reference) PCS or spectral values.\n");
fprintf(stderr," measured.ti3 Measured (actual) PCS or spectral values\n");
exit(1);
@@ -113,6 +115,7 @@ int main(int argc, char *argv[])
{
int fa,nfa,mfa; /* current argument we're looking at */
int verb = 0; /* Verbose level */
+ int useloc = 0; /* Match patches by sample location */
int norm = 0; /* 1 = norm to White Y, 2 = norm to White XYZ */
/* 3 = norm to White X+Y+Z, 4 = norm to average XYZ */
int usestdd50 = 0; /* Use standard D50 instead of avg white as reference */
@@ -123,6 +126,7 @@ int main(int argc, char *argv[])
int dohisto = 0; /* Plot histogram of delta E's */
char histoname[MAXNAMEL+1] = "\000"; /* Optional file to save histogram points to */
int dosort = 0;
+ int dozrep = 0; /* 1 = print average, 2 = print max */
char ccmxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction Matrix name */
ccmx *cmx = NULL; /* Colorimeter Correction Matrix */
char gprofname[MAXNAMEL+1] = "\000"; /* Gamut limit profile name */
@@ -196,6 +200,11 @@ int main(int argc, char *argv[])
}
}
+ /* Use location to match patches */
+ else if (argv[fa][1] == 'l') {
+ useloc = 1;
+ }
+
/* normalize */
else if (argv[fa][1] == 'n'
|| argv[fa][1] == 'N') {
@@ -296,10 +305,20 @@ int main(int argc, char *argv[])
spec = 1;
tillum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
spec = 1;
tillum = icxIT_custom;
- if (read_xspect(&cust_tillum, na) != 0)
+ if (read_xspect(&cust_tillum, &mt, na) != 0)
usage();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("Target illuminant '%s' is wrong measurement type",na);
+ }
}
}
}
@@ -333,10 +352,20 @@ int main(int argc, char *argv[])
spec = 1;
illum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
spec = 1;
illum = icxIT_custom;
- if (read_xspect(&cust_illum, na) != 0)
+ if (read_xspect(&cust_illum, &mt, na) != 0)
usage();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("CIE illuminant '%s' is wrong measurement type",na);
+ }
}
}
@@ -375,6 +404,17 @@ int main(int argc, char *argv[])
if (na == NULL) usage();
fa = nfa;
strncpy(ccmxname,na,MAXNAMEL-1); ccmxname[MAXNAMEL-1] = '\000';
+ }
+
+ else if (argv[fa][1] == 'Z') {
+ if (na == NULL) usage();
+ fa = nfa;
+ if (strcmp(na, "A") == 0) {
+ dozrep = 1;
+ } else if (strcmp(na, "X") == 0) {
+ dozrep = 2;
+ } else
+ usage();
} else
usage();
@@ -555,9 +595,8 @@ int main(int argc, char *argv[])
if ((sidx = cgf->find_field(cgf, 0, "SAMPLE_ID")) < 0
&& (sidx = cgf->find_field(cgf, 0, "SampleName")) < 0
&& (sidx = cgf->find_field(cgf, 0, "Sample_Name")) < 0
- && (sidx = cgf->find_field(cgf, 0, "SAMPLE_NAME")) < 0
- && (sidx = cgf->find_field(cgf, 0, "SAMPLE_LOC")) < 0)
- error("Input file '%s' doesn't contain field SAMPLE_ID, SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_LOC",cg[n].name);
+ && (sidx = cgf->find_field(cgf, 0, "SAMPLE_NAME")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_ID, SampleName, Sample_Name, SAMPLE_NAME",cg[n].name);
if (cgf->t[0].ftype[sidx] != nqcs_t
&& cgf->t[0].ftype[sidx] != cs_t)
error("Sample ID/Name field isn't a quoted or non quoted character string");
@@ -608,8 +647,8 @@ int main(int argc, char *argv[])
cg[n].pat[i].xyz[1] = *((double *)cgf->t[0].fdata[i][yix]);
cg[n].pat[i].xyz[2] = *((double *)cgf->t[0].fdata[i][zix]);
- if (isLab) { /* Convert Lab to XYZ */
- icmLab2XYZ(&icmD50, cg[n].pat[i].xyz, cg[n].pat[i].xyz);
+ if (isLab) { /* Convert Lab to XYZ 0..100% */
+ icmLab2XYZ(&icmD50_100, cg[n].pat[i].xyz, cg[n].pat[i].xyz);
}
//printf("~1 file %d patch %d = XYZ %f %f %f\n", n,i,cg[n].pat[i].xyz[0],cg[n].pat[i].xyz[1],cg[n].pat[i].xyz[2]);
@@ -896,15 +935,37 @@ int main(int argc, char *argv[])
/* Create a list to map the second list of patches to the first */
if ((match = (int *)malloc(sizeof(int) * cg[0].npat)) == NULL)
error("Malloc failed - match[]");
- for (i = 0; i < cg[0].npat; i++) {
- for (j = 0; j < cg[1].npat; j++) {
- if (strcmp(cg[0].pat[i].sid, cg[1].pat[j].sid) == 0)
- break; /* Found it */
+
+ /* Use location to match */
+ if (useloc) {
+ for (i = 0; i < cg[0].npat; i++) {
+ if (cg[0].pat[0].loc == '\000'
+ || cg[1].pat[0].loc == '\000')
+ error("Need both files to have SAMPLE_LOC field to match on location");
+
+ for (j = 0; j < cg[1].npat; j++) {
+ if (strcmp(cg[0].pat[i].loc, cg[1].pat[j].loc) == 0)
+ break; /* Found it */
+ }
+ if (j < cg[1].npat) {
+ match[i] = j;
+ } else {
+ error("Failed to find matching patch to '%s'",cg[0].pat[i].loc);
+ }
}
- if (j < cg[1].npat) {
- match[i] = j;
- } else {
- error("Failed to find matching patch to '%s'",cg[0].pat[i].sid);
+
+ /* Use id */
+ } else {
+ for (i = 0; i < cg[0].npat; i++) {
+ for (j = 0; j < cg[1].npat; j++) {
+ if (strcmp(cg[0].pat[i].sid, cg[1].pat[j].sid) == 0)
+ break; /* Found it */
+ }
+ if (j < cg[1].npat) {
+ match[i] = j;
+ } else {
+ error("Failed to find matching patch to '%s'",cg[0].pat[i].sid);
+ }
}
}
@@ -1329,7 +1390,7 @@ int main(int argc, char *argv[])
double de = cg[0].pat[sort[i]].de;
if (cg[0].pat[i].og) /* Skip out of gamut */
continue;
- if (j <= n10) { /* If in worst 10% of in gamut patches */
+ if (j < n10) { /* If in worst 10% of in gamut patches */
aerr10 += de;
if (de > merr10)
merr10 = de;
@@ -1343,24 +1404,36 @@ int main(int argc, char *argv[])
fprintf(verbo,"No of test patches in worst 10%% are = %d\n",n10);
fprintf(verbo,"No of test patches in best 90%% are = %d\n",n90);
}
- printf("Verify results:\n");
- if (norm == 4)
- printf(" L*a*b* ref. = average XYZ %f %f %f\n",cg[0].w[0],cg[0].w[1],cg[0].w[2]);
- else if (norm == 1) {
- printf(" File 1 L* ref. Y %f\n", cg[0].w[1]);
- printf(" File 2 L* ref. Y %f\n", cg[1].w[1]);
- } else if (norm == 2) {
- printf(" File 1 L*a*b* ref. XYZ %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]);
- printf(" File 2 L*a*b* ref. XYZ %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]);
- } else if (norm == 3) {
- printf(" File 1 L* ref. X+Y+Z %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]);
- printf(" File 2 L* ref. X+Y+Z %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]);
+
+ /* Single number report */
+ if (dozrep != 0) {
+ if (dozrep == 1) {
+ printf(" %f\t", aerr);
+ } else if (dozrep == 2) {
+ printf(" %f\t", merr);
+ }
+ fflush(stdout);
+
+ } else {
+ printf("Verify results:\n");
+ if (norm == 4)
+ printf(" L*a*b* ref. = average XYZ %f %f %f\n",cg[0].w[0],cg[0].w[1],cg[0].w[2]);
+ else if (norm == 1) {
+ printf(" File 1 L* ref. Y %f\n", cg[0].w[1]);
+ printf(" File 2 L* ref. Y %f\n", cg[1].w[1]);
+ } else if (norm == 2) {
+ printf(" File 1 L*a*b* ref. XYZ %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]);
+ printf(" File 2 L*a*b* ref. XYZ %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]);
+ } else if (norm == 3) {
+ printf(" File 1 L* ref. X+Y+Z %f %f %f\n", cg[0].w[0],cg[0].w[1],cg[0].w[2]);
+ printf(" File 2 L* ref. X+Y+Z %f %f %f\n", cg[1].w[0],cg[1].w[1],cg[1].w[2]);
+ }
+ printf(" Total errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr, aerr);
+ printf(" Worst 10%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr10, aerr10);
+ printf(" Best 90%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr90, aerr90);
+ printf(" avg err X %f, Y %f, Z %f\n", aixerr[0], aixerr[1], aixerr[2]);
+ printf(" avg err L* %f, a* %f, b* %f\n", aierr[0], aierr[1], aierr[2]);
}
- printf(" Total errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr, aerr);
- printf(" Worst 10%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr10, aerr10);
- printf(" Best 90%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr90, aerr90);
- printf(" avg err X %f, Y %f, Z %f\n", aixerr[0], aixerr[1], aixerr[2]);
- printf(" avg err L* %f, a* %f, b* %f\n", aierr[0], aierr[1], aierr[2]);
free(sort);
free(match);
diff --git a/profile/invprofcheck.c b/profile/invprofcheck.c
index 5cb1101..0d6176c 100644
--- a/profile/invprofcheck.c
+++ b/profile/invprofcheck.c
@@ -38,7 +38,6 @@
#include "icc.h"
#include "xicc.h"
#include "vrml.h"
-#include "ui.h"
/* Resolution of the sampling modes */
#define TRES 11
diff --git a/profile/prof.h b/profile/prof.h
index 013fbd6..486c5b8 100644
--- a/profile/prof.h
+++ b/profile/prof.h
@@ -56,15 +56,19 @@ void make_output_icc(
char *file_name, /* output icc name */
cgats *icg, /* input cgats structure */
int spec, /* Use spectral data flag */
- icxIllumeType tillum, /* Target/simulated instrument illuminant */
- xspect *cust_tillum, /* Possible custom target/simulated instrument illumination */
- icxIllumeType illum, /* Spectral illuminant */
- xspect *cust_illum, /* Possible custom illumination */
- icxObserverType observ, /* Spectral observer */
+ icxIllumeType tillum, /* Target/simulated instrument illuminant, if set. */
+ xspect *cust_tillum, /* Custom target/simulated illumination spectrum */
+ /* if tillum == icxIT_custom */
+ icxIllumeType illum, /* CIE calc. illuminant spectrum, and FWA inst. */
+ /* illuminant if tillum not set. */
+ xspect *cust_illum, /* Custom CIE illumination spectrum if illum == icxIT_custom */
+ icxObserverType observ, /* CIE calc. observer */
int fwacomp, /* FWA compensation requested */
double smooth, /* RSPL smoothing factor, -ve if raw */
double avgdev, /* reading Average Deviation as a proportion of the input range */
double demph, /* Emphasise dark region grid resolution in cLUT */
+ int gcompr, /* Gamut compression % if > 0 rather than ipname */
+ int gexpr, /* Gamut saturation expansion % if gcompr > 0 rather */
char *ipname, /* input icc profile - enables gamut map, NULL if none */
char *sgname, /* source image gamut - NULL if none */
char *absname[3], /* abstract profile name for each table */
diff --git a/profile/profcheck.c b/profile/profcheck.c
index e3f1bec..c5703da 100644
--- a/profile/profcheck.c
+++ b/profile/profcheck.c
@@ -294,10 +294,20 @@ int main(int argc, char *argv[])
spec = 1;
tillum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
spec = 1;
tillum = icxIT_custom;
- if (read_xspect(&cust_tillum, na) != 0)
+ if (read_xspect(&cust_tillum, &mt, na) != 0)
usage();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("Target illuminant '%s' is wrong measurement type",na);
+ }
}
}
}
@@ -330,10 +340,20 @@ int main(int argc, char *argv[])
spec = 1;
illum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
spec = 1;
illum = icxIT_custom;
- if (read_xspect(&cust_illum, na) != 0)
+ if (read_xspect(&cust_illum, &mt, na) != 0)
usage();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("CIE illuminant '%s' is wrong measurement type",na);
+ }
}
}
diff --git a/profile/profin.c b/profile/profin.c
index 4db596c..9287cf9 100644
--- a/profile/profin.c
+++ b/profile/profin.c
@@ -1164,6 +1164,7 @@ make_input_icc(
flags |= ICX_VERBOSE;
flags |= ICX_CLIP_NEAREST; /* Not vector clip */
+
#ifdef USE_CAM_CLIP_OPT
flags |= ICX_CAM_CLIP; /* Clip in CAM Jab space rather than Lab */
#else
diff --git a/profile/profout.c b/profile/profout.c
index 4ad62aa..f12589b 100644
--- a/profile/profout.c
+++ b/profile/profout.c
@@ -38,13 +38,21 @@
* Fix error handling
* fix verbose output
* hand icc object back rather than writing file ?
+ *
+ * In theory we could add a ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD option
+ * for the case of a non-D50 illuminant. spec2cie (and colprof internally) would
+ * have to put the illuminant white point in the .ti3 file and chromatically
+ * transform the XYZ/Lab values, and then colprof would create the chad tag
+ * with the illuminant to D50 matrix. icclib would have to undo the
+ * transform for absolute intent.
*/
/*
Outline of code flow:
profout:
- Create ICC profile and all the tags. Table tags are initialy not set.
+ Create ICC profile and all the tags, and setup any options.
+ Table tags are initialy not set.
Read in the CGTATS data and convert spectral to PCS if needed.
@@ -164,8 +172,8 @@ typedef struct {
double filter_thr; /* Clip DE threshold */
double filter_ratio; /* Clip DE to radius factor */
double filter_maxrad; /* Clip maximum filter radius */
- icColorSpaceSignature pcsspace; /* The PCS colorspace */
- icColorSpaceSignature devspace; /* The device colorspace */
+ icColorSpaceSignature pcsspace; /* The profile PCS colorspace */
+ icColorSpaceSignature devspace; /* The profile device colorspace */
icxLuLut *x; /* A2B icxLuLut we are inverting in std PCS */
int ntables; /* Number of tables being set. 1 = colorimetric */
@@ -176,6 +184,8 @@ typedef struct {
icxLuBase *ixp; /* Source profile perceptual PCS to CAM conversion */
icxLuBase *ox; /* Destination profile CAM to std PCS conversion */
/* (This is NOT used for the colorimetric B2A table creation!) */
+ icxcam *icam; /* Alternate to ixp when using default general compression */
+ icColorSpaceSignature mapsp; /* output space needed from icam conversion */
/* Abstract transform for each table. These may be */
/* duplicates. */
@@ -406,8 +416,25 @@ void out_b2a_clut(void *cntx, double *out, double in[3]) {
}
DBG(("convert PCS' to PCS got %f %f %f\n",in1[0],in1[1],in1[2]))
- /* Convert from PCS to CAM/Gamut mapping space */
- p->ixp->fwd_relpcs_outpcs(p->ixp, p->pcsspace, in1, in1);
+ /* Convert from profile PCS to CAM/Gamut mapping space */
+ if (p->ixp != NULL) {
+ p->ixp->fwd_relpcs_outpcs(p->ixp, p->pcsspace, in1, in1);
+
+ } else { /* General compression fallback conversion to CAM/Gamut mapping space */
+
+ if (p->mapsp == icxSigJabData) { /* Want icxSigJabData for mapping */
+
+ if (p->pcsspace == icSigLabData)
+ icmLab2XYZ(&icmD50, in1, in1);
+
+ p->icam->XYZ_to_cam(p->icam, in1, in1);
+
+ } else { /* Must be icSigLabData for mapping */
+
+ if (p->pcsspace == icSigXYZData)
+ icmXYZ2Lab(&icmD50, in1, in1);
+ }
+ }
DBG(("convert PCS to CAM got %f %f %f\n",in1[0],in1[1],in1[2]))
@@ -651,15 +678,19 @@ make_output_icc(
char *file_name, /* output icc name */
cgats *icg, /* input cgats structure */
int spec, /* Use spectral data flag */
- icxIllumeType tillum, /* Target/simulated instrument illuminant */
- xspect *cust_tillum, /* Possible custom target/simulated instrument illumination */
- icxIllumeType illum, /* Spectral illuminant */
- xspect *cust_illum, /* Possible custom illumination */
- icxObserverType observ, /* Spectral observer */
+ icxIllumeType tillum, /* Target/simulated instrument illuminant, if set. */
+ xspect *cust_tillum, /* Custom target/simulated illumination spectrum */
+ /* if tillum == icxIT_custom */
+ icxIllumeType illum, /* CIE calc. illuminant spectrum, and FWA inst. */
+ /* illuminant if tillum not set. */
+ xspect *cust_illum, /* Custom CIE illumination spectrum if illum == icxIT_custom */
+ icxObserverType observ, /* CIE calc. observer */
int fwacomp, /* FWA compensation requested */
double smooth, /* RSPL smoothing factor, -ve if raw */
double avgdev, /* reading Average Deviation as a proportion of the input range */
double demph, /* Emphasise dark region grid resolution in cLUT */
+ int gcompr, /* Gamut compression % if > 0, rather than use ipname */
+ int gexpr, /* Gamut saturation expansion % if gcompr > 0 rather */
char *ipname, /* input icc profile - enables gamut map, NULL if none */
char *sgname, /* source image gamut - NULL if none */
char *absname[3], /* abstract profile name for each table */
@@ -676,6 +707,8 @@ make_output_icc(
double dispLuminance = 0.0; /* Display luminance. 0.0 if not known */
int isdnormed = 0; /* Has display data been normalised to white Y = 100 ? */
int allintents; /* nz if all intents should possibly be created */
+ double *ill_wp = NULL; /* If illum is not D50, illum white point XYZ */
+ double _ill_wp[3]; /* (What ill_wp points at if it is not NULL) */
icmFile *wr_fp;
icc *wr_icco;
int npat; /* Number of patches */
@@ -727,7 +760,7 @@ make_output_icc(
if (strcmp(icg->t[0].kdata[ti],"DISPLAY") == 0) {
isdisp = 1;
- if (isLut && ipname != NULL)
+ if (isLut && (ipname != NULL || gcompr > 0))
allintents = 1;
else
allintents = 0; /* Only the default intent */
@@ -757,6 +790,28 @@ make_output_icc(
}
}
+ /* See if CIE illuminant white point is given, in case CIE data */
+ /* is used, and 'chad' tag is going to be created. */
+ if (!isdisp) {
+ int ti;
+
+ if ((ti = icg->find_kword(icg, 0, "ILLUMINANT_WHITE_POINT_XYZ")) >= 0) {
+ if (sscanf(icg->t[0].kdata[ti], " %lf %lf %lf ",&_ill_wp[0],&_ill_wp[1],&_ill_wp[2]) == 3) {
+
+ /* Normalize it */
+ if (_ill_wp[1] > 1e-6) {
+ _ill_wp[0] /= _ill_wp[1];
+ _ill_wp[2] /= _ill_wp[1];
+ _ill_wp[1] = 1.0;
+
+ ill_wp = _ill_wp;
+ }
+ }
+ if (verb)
+ fprintf(verbo,"Unable to parse 'ILLUMINANT_WHITE_POINT_XYZ' keyword\n");
+ }
+ }
+
/* Figure out what sort of device colorspace it is */
{
int ti;
@@ -1309,7 +1364,7 @@ make_output_icc(
if (allintents) { /* All the intents may be needed */
- if (ipname == NULL) { /* No gamut mapping */
+ if (ipname == NULL && gcompr <= 0) { /* No gamut mapping */
icmLut *wo;
/* link intent 0 = perceptual to intent 1 = colorimetric */
@@ -1476,7 +1531,7 @@ make_output_icc(
if (fseek(fp, 0, SEEK_END))
error("Unable to seek to end of file '%s'",in_name);
wo->size = ftell(fp) + 1; /* Size needed + null */
- wo->allocate((icmBase *)wo);/* Allocate space */
+ wo->allocate((icmBase *)wo); /* Allocate space */
if (fseek(fp, 0, SEEK_SET))
error("Unable to seek to end of file '%s'",in_name);
@@ -1730,6 +1785,16 @@ make_output_icc(
cust_illum = NULL;
}
+ /* If CIE calculation illuminant is not standard, compute it's white point, */
+ /* in case we are going to create 'chad' tag. */
+ if (!isdisp && illum != icxIT_D50) {
+ ill_wp = _ill_wp;
+
+ /* Compute XYZ of illuminant */
+ if (icx_ill_sp2XYZ(ill_wp, observ, NULL, illum, 0.0, cust_illum) != 0)
+ error("icx_ill_sp2XYZ returned error");
+ }
+
/* Create a spectral conversion object */
if ((sp2cie = new_xsp2cie(illum, cust_illum, observ, NULL,
wantLab ? icSigLabData : icSigXYZData, icxClamp)) == NULL)
@@ -1902,6 +1967,12 @@ make_output_icc(
} /* End of reading in CGATs file */
+ /* If we have been given an illuminant white point, set this in the */
+ /* ICC profile so that it can save a 'chad' tag if */
+ /* ARGYLL_CREATE_OUTPUT_PROFILE_WITH_CHAD is set. */
+ if (ill_wp != NULL)
+ wr_icco->set_illum(wr_icco, ill_wp);
+
#ifdef EMPH_DISP_BLACKPOINT
/* Add extra weighting to sample points near black for additive display. */
/* Not sure what the justification is, apart from making the black */
@@ -2000,6 +2071,7 @@ make_output_icc(
error("Creation of xicc failed");
flags |= ICX_CLIP_NEAREST; /* This will avoid clip caused rev setup */
+ /* which we don't need when creating A2B */
if (noisluts)
flags |= ICX_NO_IN_SHP_LUTS;
@@ -2082,13 +2154,12 @@ make_output_icc(
xicc *x;
icxViewCond *v, *vc;
int es;
+ double *wp = NULL;
if (i == 0) { /* Input */
v = ivc_p; /* Override parameters */
es = ivc_e;
vc = &ivc; /* Target parameters */
- if (src_xicc == NULL)
- continue; /* Source viewing conditions won't be used */
x = src_xicc;
} else { /* Output */
v = ovc_p; /* Override parameters */
@@ -2096,13 +2167,16 @@ make_output_icc(
vc = &ovc; /* Target parameters */
x = wr_xicc;
}
+
+ if (x == NULL)
+ wp = icmD50_ary3; /* So xicc_enum_viewcond will work without xicc */
/* Set the default */
- xicc_enum_viewcond(x, vc, -1, NULL, 0, NULL);
+ xicc_enum_viewcond(x, vc, -1, NULL, 0, wp);
/* Override the viewing conditions */
if (es >= 0)
- if (xicc_enum_viewcond(x, vc, es, NULL, 0, NULL) == -2)
+ if (xicc_enum_viewcond(x, vc, es, NULL, 0, wp) == -2)
error ("%d, %s",x->errc, x->err);
if (v->Ev >= 0)
vc->Ev = v->Ev;
@@ -2142,6 +2216,8 @@ make_output_icc(
vc->Gxyz[0] = x/y * vc->Gxyz[1];
vc->Gxyz[2] = z/y * vc->Gxyz[1];
}
+ if (v->hkscale >= 0.0)
+ vc->hkscale = v->hkscale;
}
/* Get a suitable forward conversion object to invert. */
@@ -2153,7 +2229,16 @@ make_output_icc(
if (verb)
flags |= ICX_VERBOSE;
- flags |= ICX_CLIP_NEAREST; /* Not vector clip */
+#ifdef NEVER /* [Und] */
+ /* Vector is somewhat flakey (some CuspMap based vectors don't 100%
+ intersect the gamut, having to fall back on nearest), and the result
+ is rather poor in saturation for green and yellow in particular. */
+ flags |= ICX_CLIP_VECTOR;
+ warning("!!!! ICX_CLIP_VECTOR in profout.c is on !!!!");
+#else
+ flags |= ICX_CLIP_NEAREST;
+#endif
+
#ifdef USE_CAM_CLIP_OPT
flags |= ICX_CAM_CLIP; /* Clip in CAM Jab space rather than Lab */
#else
@@ -2180,6 +2265,8 @@ make_output_icc(
cx.ixp = NULL; /* Perceptual PCS to CAM conversion */
cx.ox = NULL; /* CAM to PCS conversion */
+ cx.icam = NULL;
+ cx.mapsp = 0;
cx.pmap = NULL; /* perceptual gamut map */
cx.smap = NULL; /* Saturation gamut map */
@@ -2191,7 +2278,7 @@ make_output_icc(
/* Determine the number of tables */
cx.ntables = 1;
- if (src_xicc) { /* Creating separate perceptual and Saturation tables */
+ if (src_xicc || gcompr) { /* Creating separate perceptual and Saturation tables */
cx.ntables = 2;
if (sepsat)
cx.ntables = 3;
@@ -2261,16 +2348,17 @@ make_output_icc(
wr_icco, icSigBToA1Tag)) == NULL)
error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
- if (src_xicc) { /* Creating separate perceptual and Saturation tables */
+ if (src_xicc || gcompr) { /* Creating separate perceptual and Saturation tables */
icRenderingIntent intentp; /* Gamut mapping space perceptual selection */
icRenderingIntent intents; /* Gamut mapping space saturation selection */
icRenderingIntent intento; /* Gamut mapping space output selection */
- gamut *csgamp; /* Incoming colorspace perceptual gamut */
- gamut *csgams; /* Incoming colorspace saturation gamut */
- gamut *igam = NULL; /* Incoming image gamut */
- gamut *ogam; /* Destination colorspace gamut */
- double gres; /* Gamut surface feature resolution */
- int mapres; /* Mapping rspl resolution */
+ gamut *csgamp = NULL; /* Incoming colorspace perceptual gamut */
+ gamut *csgams = NULL; /* Incoming colorspace saturation gamut */
+ gamut *igam = NULL; /* Incoming image gamut */
+ gamut *ogam = NULL; /* Destination colorspace gamut */
+ gamut *ihgam = NULL; /* Input space general compression hull gamut */
+ double gres; /* Gamut surface feature resolution */
+ int mapres; /* Mapping rspl resolution */
if (verb)
printf("Creating Gamut Mapping\n");
@@ -2353,50 +2441,56 @@ make_output_icc(
/* Unlike icclink, we've not provided a way for the user */
/* to set the source profile ink limit, so estimate it */
/* from the profile */
- icxDefaultLimits(src_xicc, &iink.tlimit, iink.tlimit,
- &iink.klimit, iink.klimit);
-
- /* Get lookup object simply for fwd_relpcs_outpcs() */
- /* and perceptual input gamut shell creation. */
- /* Note that the intent=Appearance will trigger Jab CAM, */
- /* overriding icSigLabData.. */
-#ifdef NEVER
- printf("~1 input space flags = 0x%x\n",ICX_CLIP_NEAREST);
- printf("~1 input space intent = %s\n",icx2str(icmRenderingIntent,intentp));
- printf("~1 input space pcs = %s\n",icx2str(icmColorSpaceSignature,icSigLabData));
- printf("~1 input space viewing conditions =\n"); xicc_dump_viewcond(&ivc);
- printf("~1 input space inking =\n"); xicc_dump_inking(&iink);
-#endif
- if ((cx.ixp = src_xicc->get_luobj(src_xicc,ICX_CLIP_NEAREST
- , icmFwd, intentp, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL)
- error ("%d, %s",src_xicc->errc, src_xicc->err);
+ if (src_xicc != NULL) {
+ icxDefaultLimits(src_xicc, &iink.tlimit, iink.tlimit,
+ &iink.klimit, iink.klimit);
- /* Create the source colorspace gamut surface */
- if (verb)
- printf(" Finding Source Colorspace Perceptual Gamut\n");
-
- if ((csgamp = cx.ixp->get_gamut(cx.ixp, gres)) == NULL)
- error ("%d, %s",src_xicc->errc, src_xicc->err);
-
- if (sepsat) {
- icxLuBase *ixs = NULL; /* Source profile saturation lookup for gamut */
- /* Get lookup object for saturation input gamut shell creation */
+ /* Get lookup object simply for fwd_relpcs_outpcs() */
+ /* and perceptual input gamut shell creation. */
/* Note that the intent=Appearance will trigger Jab CAM, */
/* overriding icSigLabData.. */
- if ((ixs = src_xicc->get_luobj(src_xicc, ICX_CLIP_NEAREST
- , icmFwd, intents, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL)
- error ("%d, %s",src_xicc->errc, src_xicc->err);
-
+#ifdef NEVER
+ printf("~1 input space flags = 0x%x\n",ICX_CLIP_NEAREST);
+ printf("~1 input space intent = %s\n",icx2str(icmRenderingIntent,intentp));
+ printf("~1 input space pcs = %s\n",icx2str(icmColorSpaceSignature,icSigLabData));
+ printf("~1 input space viewing conditions =\n"); xicc_dump_viewcond(&ivc);
+ printf("~1 input space inking =\n"); xicc_dump_inking(&iink);
+#endif
+ if ((cx.ixp = src_xicc->get_luobj(src_xicc,ICX_CLIP_NEAREST
+ , icmFwd, intentp, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL)
+ error ("%d, %s",src_xicc->errc, src_xicc->err);
+
+ /* Create the source colorspace gamut surface */
if (verb)
- printf(" Finding Source Colorspace Saturation Gamut\n");
-
- if ((csgams = ixs->get_gamut(ixs, gres)) == NULL)
+ printf(" Finding Source Colorspace Perceptual Gamut\n");
+
+ if ((csgamp = cx.ixp->get_gamut(cx.ixp, gres)) == NULL)
+ error ("%d, %s",src_xicc->errc, src_xicc->err);
+
+ if (sepsat) {
+ icxLuBase *ixs = NULL; /* Source profile saturation lookup for gamut */
+ /* Get lookup object for saturation input gamut shell creation */
+ /* Note that the intent=Appearance will trigger Jab CAM, */
+ /* overriding icSigLabData.. */
+ if ((ixs = src_xicc->get_luobj(src_xicc, ICX_CLIP_NEAREST
+ , icmFwd, intents, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL)
error ("%d, %s",src_xicc->errc, src_xicc->err);
- ixs->del(ixs);
+
+ if (verb)
+ printf(" Finding Source Colorspace Saturation Gamut\n");
+
+ if ((csgams = ixs->get_gamut(ixs, gres)) == NULL)
+ error ("%d, %s",src_xicc->errc, src_xicc->err);
+ ixs->del(ixs);
+ }
}
-
+
/* Read image source gamut if provided */
- if (sgname != NULL) { /* Optional source gamut - ie. from an images */
+ /* Optional source gamut - ie. from an images, */
+ /* ignored if gcompr > 0 */
+ if (sgname != NULL && gcompr > 0)
+ warning("Image gamut ignored for general gamut compression");
+ if (sgname != NULL && gcompr == 0) {
int isJab = 0;
if ((pgmi->usecas & 0xff) >= 0x2)
@@ -2418,7 +2512,7 @@ make_output_icc(
/* At the moment it's up to the user to get this right. */
}
}
-
+
/* Get lookup object for bwd_outpcs_relpcs(), */
/* and output gamut shell creation */
/* Note that the intent=Appearance will trigger Jab CAM, */
@@ -2435,6 +2529,45 @@ make_output_icc(
if ((ogam = cx.ox->get_gamut(cx.ox, gres)) == NULL)
error ("%d, %s",wr_xicc->errc, wr_xicc->err);
+ /* General compression rather than source gamut */
+ if (gcompr > 0) {
+ /* Create alternative to ixp for conv. to Gamut maping space. */
+ if (cx.ixp == NULL) {
+ double wp[3], bp[3] = { 0.0, 0.0, 0.0 };
+ cx.mapsp = xiccIsIntentJab(intentp) ? icxSigJabData : icSigLabData;
+
+ if (cx.mapsp == icxSigJabData) {
+ cx.icam = new_icxcam(cam_default);
+ cx.icam->set_view(cx.icam, ivc.Ev, ivc.Wxyz, ivc.La, ivc.Yb, ivc.Lv,
+ ivc.Yf, ivc.Yg, ivc.Gxyz,
+ XICC_USE_HK, ivc.hkscale);
+ }
+
+ /* Create a dumy source gamut, used by new_gammap to create */
+ /* the L mapping */
+ if ((csgamp = new_gamut(0.0, cx.mapsp == icxSigJabData, 0)) == NULL)
+ error ("Creating fake input gamut failed");
+
+ if (cx.mapsp == icxSigJabData) {
+ cx.icam->XYZ_to_cam(cx.icam, wp, icmD50_ary3);
+ cx.icam->XYZ_to_cam(cx.icam, bp, bp);
+ } else {
+ icmXYZ2Lab(&icmD50, bp, icmD50_ary3);
+ icmXYZ2Lab(&icmD50, bp, bp);
+ }
+ csgamp->setwb(csgamp, wp, bp, bp);
+ csgams = csgamp;
+ }
+
+ /* Expand destination gamut cylindrically to make source hull gamut. */
+ if (verb)
+ printf(" Creating fake source gamut with compression %d%%\n",gcompr);
+ if ((ihgam = new_gamut(1.0, 0, 0)) == NULL
+ || ihgam->exp_cyl(ihgam, ogam, (100.0 + gcompr)/100.0)) {
+ error ("Creating expanded input failed");
+ }
+ }
+
if (verb)
printf(" Creating Gamut match\n");
@@ -2447,7 +2580,8 @@ make_output_icc(
/* values outside the grid range. */
/* setup perceptual gamut mapping */
- cx.pmap = new_gammap(verb, csgamp, igam, ogam, pgmi, 0, 0, 0, 0, mapres,
+ cx.pmap = new_gammap(verb, csgamp, igam, ogam, pgmi,
+ ihgam, 0, 0, 0, 0, mapres,
NULL, NULL, gamdiag ? "gammap_p.wrl" : NULL
);
if (cx.pmap == NULL)
@@ -2459,8 +2593,24 @@ make_output_icc(
error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
if (sepsat) {
+ /* General expansion rather than source gamut */
+ if (gcompr > 0) {
+ if (gexpr == 0)
+ gexpr = gcompr;
+ /* Expand destination gamut cylindrically to make source gamut. */
+ if (verb)
+ printf(" Creating fake source gamut with expansion %d%%\n",gexpr);
+ if (ihgam != NULL)
+ ihgam->del(ihgam);
+ if ((ihgam = new_gamut(1.0, 0, 0)) == NULL
+ || ihgam->exp_cyl(ihgam, ogam, (100.0 - gexpr)/100.0)) {
+ error ("Creating compressed input failed");
+ }
+ }
+
/* setup saturation gamut mapping */
- cx.smap = new_gammap(verb, csgams, igam, ogam, sgmi, 0, 0, 0, 0, mapres,
+ cx.smap = new_gammap(verb, csgams, igam, ogam, sgmi,
+ ihgam, 0, 0, 0, 0, mapres,
NULL, NULL, gamdiag ? "gammap_s.wrl" : NULL
);
if (cx.smap == NULL)
@@ -2471,18 +2621,22 @@ make_output_icc(
wr_icco, icSigBToA2Tag)) == NULL)
error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
}
- csgamp->del(csgamp);
- csgamp = NULL;
- if (sepsat) {
+ if (csgams != NULL && csgams != csgamp) {
csgams->del(csgams);
csgams = NULL;
}
+ if (csgamp != NULL) {
+ csgamp->del(csgamp);
+ csgamp = NULL;
+ }
if (igam != NULL) {
igam->del(igam);
igam = NULL;
}
- ogam->del(ogam);
- ogam = NULL;
+ if (ogam != NULL) {
+ ogam->del(ogam);
+ ogam = NULL;
+ }
}
}
cx.ochan = wo[0]->outputChan;
@@ -2802,6 +2956,8 @@ make_output_icc(
cx.ixp->del(cx.ixp), cx.ixp = NULL;
if (cx.ox != NULL)
cx.ox->del(cx.ox), cx.ox = NULL;
+ if (cx.icam != NULL)
+ cx.icam->del(cx.icam), cx.icam = NULL;
if (src_xicc != NULL)
src_xicc->del(src_xicc), src_xicc = NULL;
diff --git a/profile/txt2ti3.c b/profile/txt2ti3.c
index 28f5071..662fdc3 100644
--- a/profile/txt2ti3.c
+++ b/profile/txt2ti3.c
@@ -45,6 +45,8 @@
#include "numlib.h"
#include "ui.h"
+static int trans(char *dst, char *src);
+
void
usage(char *mes) {
fprintf(stderr,"Convert Gretag/Logo or X-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data, Version %s\n",ARGYLL_VERSION_STR);
@@ -57,6 +59,7 @@ usage(char *mes) {
fprintf(stderr," -l limit set ink limit, 0 - 400%% (default max in file)\n");
fprintf(stderr," -d Set type of device as Display, not Output\n");
fprintf(stderr," -i Set type of device as Input, not Output\n");
+ fprintf(stderr," -T Transpose sample name Letters and Numbers\n");
fprintf(stderr," [devfile] Input Device CMYK target file (typically file.txt)\n");
fprintf(stderr," infile Input CIE, Spectral or Device & Spectral file (typically file.txt)\n");
fprintf(stderr," [specfile] Input Spectral file (typically file.txt)\n");
@@ -72,11 +75,13 @@ int main(int argc, char *argv[])
int out2 = 0; /* Create dumy .ti2 file output */
int disp = 0; /* nz if this is a display device */
int inp = 0; /* nz if this is an input device */
+ int transpose = 0; /* nz to transpose letters and numbers */
static char devname[MAXNAMEL+1] = { 0 }; /* Input CMYK/Device .txt file (may be null) */
static char ciename[MAXNAMEL+1] = { 0 }; /* Input CIE .txt file (may be null) */
static char specname[MAXNAMEL+1] = { 0 }; /* Input Device / Spectral .txt file */
static char outname[MAXNAMEL+9] = { 0 }; /* Output cgats .ti3 file base name */
static char outname2[MAXNAMEL+9] = { 0 }; /* Output cgats .ti2 file base name */
+ int ti; /* Temporary field index */
cgats *cmy = NULL; /* Input RGB/CMYK reference file */
int f_id1 = -1, f_c, f_m, f_y, f_k = 0; /* Field indexes */
double dev_scale = 1.0; /* Device value scaling */
@@ -91,6 +96,7 @@ int main(int argc, char *argv[])
time_t clk = time(0);
struct tm *tsp = localtime(&clk);
char *atm = asctime(tsp); /* Ascii time */
+ char *devcalstd = NULL; /* X-Rite calibration standard if any */
int islab = 0; /* CIE is Lab rather than XYZ */
int specmin = 0, specmax = 0, specnum = 0; /* Min and max spectral in nm, inclusive */
int npat = 0; /* Number of patches */
@@ -143,6 +149,9 @@ int main(int argc, char *argv[])
disp = 0;
inp = 1;
+ } else if (argv[fa][1] == 'T') {
+ transpose = 1;
+
} else if (argv[fa][1] == 'v')
verb = 1;
else
@@ -309,6 +318,9 @@ int main(int argc, char *argv[])
&& cmy->t[0].ftype[f_id2] != i_t)
error("Field SampleName (%s) from cie file '%s' is wrong type",ncie->t[0].fsym[f_id2],ciename);
+ if ((ti = ncie->find_kword(ncie, 0, "DEVCALSTD")) >= 0)
+ devcalstd = ncie->t[0].kdata[ti];
+
if (ncie->find_field(ncie, 0, "XYZ_X") < 0
&& ncie->find_field(ncie, 0, "LAB_L") < 0) {
@@ -359,7 +371,7 @@ int main(int argc, char *argv[])
/* Open up the input Spectral device data file */
if (specname[0] != '\000') {
- char bufs[5][50];
+ char bufs[6][50];
spec = new_cgats(); /* Create a CGATS structure */
spec->add_other(spec, "LGOROWLENGTH"); /* Gretag/Logo Target file */
@@ -390,12 +402,14 @@ int main(int argc, char *argv[])
sprintf(bufs[2],"SPECTRAL_NM_%03d", specmin);
sprintf(bufs[3],"R_%03d", specmin);
sprintf(bufs[4],"SPECTRAL_%03d", specmin);
+ sprintf(bufs[5],"SPECTRAL_NM%03d", specmin);
if (spec->find_field(spec, 0, bufs[0]) < 0
&& spec->find_field(spec, 0, bufs[1]) < 0
&& spec->find_field(spec, 0, bufs[2]) < 0
&& spec->find_field(spec, 0, bufs[3]) < 0
- && spec->find_field(spec, 0, bufs[4]) < 0) /* Not found */
+ && spec->find_field(spec, 0, bufs[4]) < 0
+ && spec->find_field(spec, 0, bufs[5]) < 0) /* Not found */
break;
}
specmin += 10;
@@ -405,12 +419,14 @@ int main(int argc, char *argv[])
sprintf(bufs[2],"SPECTRAL_NM_%03d", specmax);
sprintf(bufs[3],"R_%03d", specmax);
sprintf(bufs[4],"SPECTRAL_%03d", specmax);
+ sprintf(bufs[5],"SPECTRAL_NM%03d", specmax);
if (spec->find_field(spec, 0, bufs[0]) < 0
&& spec->find_field(spec, 0, bufs[1]) < 0
&& spec->find_field(spec, 0, bufs[2]) < 0
&& spec->find_field(spec, 0, bufs[3]) < 0
- && spec->find_field(spec, 0, bufs[4]) < 0) /* Not found */
+ && spec->find_field(spec, 0, bufs[4]) < 0
+ && spec->find_field(spec, 0, bufs[5]) < 0) /* Not found */
break;
}
specmax -= 10;
@@ -419,6 +435,8 @@ int main(int argc, char *argv[])
spec->del(spec);
spec = NULL;
specname[0] = '\000';
+ if (verb)
+ printf("Not enough (%d) spectral values - discarding spectral\n",specnum);
} else {
specnum = (specmax - specmin)/10 + 1;
@@ -434,12 +452,14 @@ int main(int argc, char *argv[])
sprintf(bufs[2],"SPECTRAL_NM_%03d", specmin + 10 * j);
sprintf(bufs[3],"R_%03d", specmin + 10 * j);
sprintf(bufs[4],"SPECTRAL_%03d", specmin + 10 * j);
+ sprintf(bufs[5],"SPECTRAL_NM%03d", specmin + 10 * j);
if ((spi[j] = spec->find_field(spec, 0, bufs[0])) < 0
&& (spi[j] = spec->find_field(spec, 0, bufs[1])) < 0
&& (spi[j] = spec->find_field(spec, 0, bufs[2])) < 0
&& (spi[j] = spec->find_field(spec, 0, bufs[3])) < 0
- && (spi[j] = spec->find_field(spec, 0, bufs[4])) < 0) { /* Not found */
+ && (spi[j] = spec->find_field(spec, 0, bufs[4])) < 0
+ && (spi[j] = spec->find_field(spec, 0, bufs[5])) < 0) { /* Not found */
spec->del(spec);
spec = NULL;
@@ -477,10 +497,13 @@ int main(int argc, char *argv[])
/* Assume this - could try reading from file INSTRUMENTATION "SpectroScan" ?? */
ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(instSpectrolino) , NULL);
+ if (devcalstd != NULL)
+ ocg->add_kword(ocg, 0, "DEVCALSTD", devcalstd, NULL);
+
/* Fields we want */
ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
if (f_id1 >= 0)
- ocg->add_field(ocg, 0, "SAMPLE_NAME", cs_t);
+ ocg->add_field(ocg, 0, "SAMPLE_LOC", cs_t);
if (ndchan == 3) {
ocg->add_field(ocg, 0, "RGB_R", r_t);
@@ -606,6 +629,7 @@ int main(int argc, char *argv[])
/* Write out the patch info to the output CGATS file */
for (i = 0; i < npat; i++) {
char id[100];
+ char loc[100];
int k = 0;
if (ncie != NULL) {
@@ -631,8 +655,15 @@ int main(int argc, char *argv[])
setel[k++].c = id;
/* SAMPLE NAME */
- if (f_id1 >= 0)
- setel[k++].c = (char *)cmy->t[0].rfdata[i][f_id1];
+ if (f_id1 >= 0) {
+ strcpy(loc, (char *)cmy->t[0].rfdata[i][f_id1]);
+
+ /* Transpose Letters and Numbers */
+ if (transpose)
+ trans(loc, (char *)cmy->t[0].rfdata[i][f_id1]);
+
+ setel[k++].c = loc;
+ }
if (ndchan == 3) {
setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_c]);
@@ -828,4 +859,88 @@ int main(int argc, char *argv[])
}
+/* Transpose Letters and Numbers of location */
+/* return nz on error */
+static int trans(char *dst, char *src) {
+ int tt = 0, first = 0, second = 0; /* 1..n */
+ char *c, *d; /* Dividing point */
+
+//printf("\nGot '%s'\n",src);
+ d = src;
+
+ if (*d == '\000')
+ return 1;
+
+ if ((*d >= 'A' && *d <= 'Z')
+ || (*d >= 'a' && *d <= 'z'))
+ tt = 1; // Initial is letters
+ else
+ tt = 0;
+//printf("Initial is %s\n",tt ? "letters" : "numbers");
+
+ for (; ; d++) {
+ if (*d == '\000') {
+//printf("Failed to find division\n");
+ return 1;
+ }
+ if (tt && *d >= '0' && *d <= '9') {
+//printf("Found number at offset %d\n",d - src);
+ break;
+
+ } else if (!tt && ((*d >= 'A' && *d <= 'Z')
+ || (*d >= 'a' && *d <= 'z'))) {
+//printf("Found letter at offset %d\n",d - src);
+ break;
+ }
+ }
+
+
+//printf("2nd seg = '%s'\n",d);
+
+ for (c = src; c < d; c++) {
+ if (tt) {
+ if (*c >= 'A' && *c <= 'Z')
+ first = first * 26 + (*c - 'A' + 1);
+ else
+ first = first * 26 + (*c - 'a' + 1);
+ } else {
+ first = first * 10 + (*c - '0');
+ }
+ }
+ for (; *c != '\000'; c++) {
+ if (!tt) {
+ if (*c >= 'A' && *c <= 'Z')
+ second = second * 26 + (*c - 'A' + 1);
+ else
+ second = second * 26 + (*c - 'a' + 1);
+ } else {
+ second = second * 10 + (*c - '0');
+ }
+ }
+//printf("First = %d, second = %d\n",first,second);
+
+ c = dst;
+ if (tt) { /* Output letters */
+ if (second > 26) {
+ *c++ = 'A' + ((second-1) / 26) -1;
+ second = ((second-1) % 26) + 1;
+ }
+ *c++ = 'A' + second -1;
+ } else { /* Output letters */
+ c += sprintf(c, "%d",second);
+ }
+ if (tt) { /* Output letters */
+ c += sprintf(c, "%d",first);
+ } else { /* Output numbers */
+ if (first > 26) {
+ *c++ = 'A' + ((first-1) / 26) -1;
+ first = ((first-1) % 26) + 1;
+ }
+ *c++ = 'A' + first -1;
+ }
+ *c = '\000';
+//printf("Output '%s'\n",dst);
+
+ return 0;
+}
diff --git a/ref/CMP_Digital_Target-7.cht b/ref/CMP_Digital_Target-7.cht
new file mode 100644
index 0000000..d188517
--- /dev/null
+++ b/ref/CMP_Digital_Target-7.cht
@@ -0,0 +1,638 @@
+
+BOXES 571
+ F _ _ 100 200 3100 200 3100 2100 100 2100
+ D ALL ALL _ _ 3200 2100 0 100 0 0
+ X A Z 1 19 100 100 100 200 100 100
+ X 2A 2D 1 19 100 100 2700 200 100 100
+
+BOX_SHRINK 12
+
+REF_ROTATION 0.0
+
+XLIST 31
+ 100 1 1
+ 200 1 1
+ 300 1 1
+ 400 1 1
+ 500 1 1
+ 600 1 1
+ 700 1 1
+ 800 1 1
+ 900 1 1
+ 1000 1 1
+ 1100 1 1
+ 1200 1 1
+ 1300 1 1
+ 1400 1 1
+ 1500 1 1
+ 1600 1 1
+ 1700 1 1
+ 1800 1 1
+ 1900 1 1
+ 2000 1 1
+ 2100 1 1
+ 2200 1 1
+ 2300 1 1
+ 2400 1 1
+ 2500 1 1
+ 2600 1 1
+ 2700 1 1
+ 2800 1 1
+ 2900 1 1
+ 3000 1 1
+ 3100 1 1
+
+YLIST 21
+ 200 1 1
+ 300 1 1
+ 400 1 1
+ 500 1 1
+ 600 1 1
+ 700 1 1
+ 800 1 1
+ 900 1 1
+ 1000 1 1
+ 1100 1 1
+ 1200 1 1
+ 1300 1 1
+ 1400 1 1
+ 1500 1 1
+ 1500 1 1
+ 1600 1 1
+ 1700 1 1
+ 1800 1 1
+ 1900 1 1
+ 2000 1 1
+ 2100 1 1
+
+EXPECTED XYZ 570
+ A1 31.9 22.6 21.2
+ A2 7.6 21.5 7.5
+ A3 72.2 69.4 57.8
+ A4 20.9 34.4 14.4
+ A5 79.8 83.0 57.4
+ A6 37.7 36.5 30.8
+ A7 13.6 14.4 45.1
+ A8 65.7 60.9 23.2
+ A9 24.7 16.2 33.1
+ A10 2.5 1.4 7.6
+ A11 31.1 15.9 1.3
+ A12 29.7 32.5 50.3
+ A13 10.4 15.3 28.4
+ A14 18.4 28.1 7.1
+ A15 12.1 19.0 18.5
+ A16 29.9 47.3 21.8
+ A17 19.8 14.3 30.7
+ A18 41.8 24.4 1.5
+ A19 12.1 11.0 36.1
+ B1 20.9 13.2 29.7
+ B2 8.7 8.5 34.4
+ B3 2.3 1.5 2.4
+ B4 20.0 15.3 37.2
+ B5 15.5 8.4 1.2
+ B6 40.6 22.0 28.0
+ B7 16.3 33.2 10.0
+ B8 9.0 23.6 7.5
+ B9 46.9 62.0 25.3
+ B10 5.0 12.8 6.1
+ B11 16.1 8.4 16.3
+ B12 41.6 57.7 10.6
+ B13 13.9 9.9 28.1
+ B14 30.7 18.0 29.8
+ B15 27.9 13.9 17.4
+ B16 34.8 18.3 1.3
+ B17 16.0 32.5 17.9
+ B18 77.1 81.7 62.3
+ B19 42.7 29.8 12.1
+ C1 17.0 34.3 13.1
+ C2 25.7 13.2 1.4
+ C3 32.5 50.1 22.9
+ C4 16.0 18.7 1.6
+ C5 32.6 32.1 54.2
+ C6 13.4 16.4 47.5
+ C7 12.8 10.1 31.5
+ C8 41.0 37.8 1.7
+ C9 40.0 29.0 36.6
+ C10 26.8 31.3 1.9
+ C11 3.5 9.5 2.3
+ C12 9.1 7.9 31.1
+ C13 18.4 28.5 2.7
+ C14 7.2 7.6 35.4
+ C15 18.9 33.4 39.7
+ C16 44.9 39.1 13.4
+ C17 2.4 1.7 9.2
+ C18 45.9 31.4 42.3
+ C19 2.0 4.2 1.5
+ D1 3.5 2.7 17.7
+ D2 19.4 21.4 42.5
+ D3 8.2 7.4 31.0
+ D4 21.7 26.2 55.4
+ D5 20.5 38.0 7.7
+ D6 48.0 31.0 5.2
+ D7 80.7 83.9 61.0
+ D8 22.4 15.0 20.4
+ D9 4.8 13.5 2.8
+ D10 9.4 23.6 13.7
+ D11 71.6 66.5 59.1
+ D12 21.1 38.6 10.1
+ D13 35.8 17.9 12.3
+ D14 57.6 67.8 59.6
+ D15 26.8 44.2 5.8
+ D16 2.0 4.9 5.4
+ D17 40.2 34.7 13.7
+ D18 6.6 9.0 4.1
+ D19 51.9 44.0 27.1
+ E1 32.3 34.5 15.5
+ E2 29.9 17.4 29.0
+ E3 39.5 42.9 15.5
+ E4 55.3 42.2 6.4
+ E5 23.8 24.5 22.9
+ E6 9.0 18.1 6.4
+ E7 10.5 8.8 31.7
+ E8 9.8 25.0 7.6
+ E9 74.1 71.0 48.7
+ E10 48.2 59.8 60.9
+ E11 47.6 31.4 1.9
+ E12 8.4 7.7 7.1
+ E13 7.4 7.4 33.5
+ E14 24.6 12.3 5.5
+ E15 27.4 26.1 22.7
+ E16 41.6 28.8 4.8
+ E17 1.2 2.8 3.2
+ E18 77.3 76.1 57.2
+ E19 45.5 60.1 4.3
+ F1 42.3 22.5 26.0
+ F2 43.9 39.2 7.1
+ F3 7.8 7.4 32.0
+ F4 12.3 15.9 46.9
+ F5 31.2 16.0 1.3
+ F6 37.9 21.6 31.1
+ F7 9.1 23.4 4.2
+ F8 19.0 12.1 28.6
+ F9 8.1 8.5 36.2
+ F10 34.7 21.2 34.1
+ F11 33.2 37.5 26.6
+ F12 72.6 80.1 26.5
+ F13 54.3 57.6 28.9
+ F14 17.5 18.8 6.2
+ F15 41.9 23.1 17.6
+ F16 37.4 36.2 54.6
+ F17 45.2 45.8 21.8
+ F18 9.2 8.0 31.4
+ F19 24.0 21.5 12.7
+ G1 15.0 17.1 13.6
+ G2 16.8 17.7 47.7
+ G3 50.7 64.8 40.5
+ G4 66.0 71.2 28.6
+ G5 19.9 36.8 25.4
+ G6 15.6 32.5 18.2
+ G7 15.3 13.4 38.6
+ G8 14.5 31.2 12.6
+ G9 57.8 44.3 21.9
+ G10 14.3 25.5 42.1
+ G11 6.4 3.7 6.6
+ G12 33.6 34.6 31.0
+ G13 4.1 6.2 16.1
+ G14 26.7 14.0 1.3
+ G15 34.9 47.5 27.1
+ G16 40.7 29.1 1.3
+ G17 37.4 20.1 1.5
+ G18 8.0 21.2 3.8
+ G19 28.9 41.3 13.5
+ H1 43.0 25.0 9.0
+ H2 38.5 21.6 1.4
+ H3 8.5 7.5 31.0
+ H4 42.0 23.7 30.9
+ H5 17.8 28.2 2.8
+ H6 1.4 1.1 4.8
+ H7 51.7 64.1 4.1
+ H8 1.8 1.5 1.8
+ H9 4.7 9.1 8.9
+ H10 22.5 42.9 28.6
+ H11 60.6 59.2 43.6
+ H12 2.6 1.7 12.1
+ H13 74.8 77.5 52.1
+ H14 23.8 40.8 23.3
+ H15 38.7 24.4 36.0
+ H16 18.1 12.8 31.6
+ H17 24.9 21.0 45.0
+ H18 30.5 18.8 30.8
+ H19 14.6 25.6 24.7
+ I1 5.7 4.0 19.0
+ I2 12.8 9.4 28.2
+ I3 29.3 44.1 3.0
+ I4 8.1 7.5 32.0
+ I5 1.4 2.0 1.2
+ I6 49.0 42.5 28.4
+ I7 7.1 7.3 34.5
+ I8 17.5 34.0 23.3
+ I9 35.8 22.1 34.9
+ I10 10.0 24.9 11.3
+ I11 6.7 7.3 1.2
+ I12 16.1 32.9 21.4
+ I13 8.6 8.9 32.0
+ I14 21.2 13.5 29.3
+ I15 7.9 8.7 34.2
+ I16 78.9 81.9 68.4
+ I17 44.3 60.2 17.1
+ I18 13.9 30.5 12.5
+ I19 13.0 7.2 1.4
+ J1 9.7 23.5 6.5
+ J2 12.4 28.5 7.7
+ J3 17.8 24.2 56.1
+ J4 76.2 80.6 47.7
+ J5 20.6 35.9 34.0
+ J6 1.9 1.4 7.7
+ J7 72.5 70.7 46.5
+ J8 0.9 0.8 2.0
+ J9 54.8 44.5 1.8
+ J10 57.7 42.8 13.1
+ J11 57.7 59.9 46.7
+ J12 14.2 6.8 15.7
+ J13 24.0 21.2 1.6
+ J14 8.1 15.3 12.5
+ J15 68.4 59.9 38.8
+ J16 17.9 15.1 6.1
+ J17 5.0 4.5 2.1
+ J18 53.3 37.1 26.2
+ J19 26.2 37.2 33.5
+ K1 17.1 11.8 29.9
+ K2 1.8 1.8 1.1
+ K3 40.6 22.8 9.9
+ K4 8.8 14.3 27.9
+ K5 35.3 20.8 31.6
+ K6 20.0 33.3 47.9
+ K7 12.2 21.3 7.6
+ K8 6.7 5.4 20.8
+ K9 12.8 18.9 30.3
+ K10 31.1 19.6 22.4
+ K11 56.6 55.4 6.7
+ K12 21.6 12.2 1.9
+ K13 25.4 38.1 57.2
+ K14 24.3 21.7 46.4
+ K15 7.9 7.4 5.5
+ K16 49.2 55.7 9.0
+ K17 33.0 49.9 31.4
+ K18 81.4 84.5 65.4
+ K19 25.8 16.6 5.3
+ L1 66.6 68.8 62.7
+ L2 37.1 36.0 26.7
+ L3 36.6 40.4 56.0
+ L4 36.6 22.5 34.7
+ L5 20.2 35.7 32.8
+ L6 31.2 30.0 13.0
+ L7 21.6 12.2 2.0
+ L8 0.8 0.8 0.7
+ L9 0.7 0.7 0.6
+ L10 0.9 0.9 0.8
+ L11 1.2 1.2 1.1
+ L12 12.2 21.2 7.5
+ L13 3.6 2.3 14.9
+ L14 26.0 12.6 6.3
+ L15 51.3 56.3 17.2
+ L16 59.3 65.3 54.1
+ L17 37.2 20.2 2.3
+ L18 14.7 11.3 5.9
+ L19 20.3 35.8 34.4
+ M1 2.5 1.9 1.2
+ M2 40.3 22.5 29.7
+ M3 21.1 42.5 14.2
+ M4 11.8 16.5 15.5
+ M5 10.3 5.9 1.2
+ M6 12.6 25.3 14.4
+ M7 56.7 55.4 6.8
+ M8 1.5 1.5 1.3
+ M9 1.5 1.6 1.3
+ M10 1.8 1.9 1.5
+ M11 1.9 1.9 1.6
+ M12 6.7 5.3 20.7
+ M13 23.4 43.2 12.5
+ M14 53.4 45.9 47.1
+ M15 22.4 20.7 37.0
+ M16 8.6 7.8 31.8
+ M17 4.6 3.1 1.3
+ M18 62.8 60.2 2.6
+ M19 3.7 2.7 1.3
+ N1 28.2 32.6 47.8
+ N2 17.8 16.7 14.7
+ N3 35.0 38.6 31.1
+ N4 28.7 14.8 1.3
+ N5 15.1 30.2 29.6
+ N6 59.7 49.0 31.7
+ N7 31.0 19.6 22.4
+ N8 2.3 2.3 1.9
+ N9 2.5 2.6 2.1
+ N10 2.7 2.8 2.3
+ N11 2.9 2.9 2.4
+ N12 13.1 18.9 30.3
+ N13 14.4 14.5 45.8
+ N14 48.3 36.3 1.0
+ N15 5.8 5.5 3.6
+ N16 17.8 32.2 19.1
+ N17 19.1 33.8 35.3
+ N18 34.8 21.1 33.0
+ N19 7.6 20.5 3.8
+ O1 29.2 45.4 39.0
+ O2 41.2 23.7 12.0
+ O3 30.4 15.5 1.3
+ O4 14.4 29.3 28.1
+ O5 1.3 1.2 1.0
+ O6 42.4 36.8 52.8
+ O7 12.9 19.0 30.5
+ O8 4.0 4.1 3.3
+ O9 5.8 6.0 4.7
+ O10 7.6 7.9 6.2
+ O11 8.5 8.8 7.0
+ O12 31.0 19.6 22.4
+ O13 40.7 33.1 14.4
+ O14 9.8 13.1 5.2
+ O15 34.6 22.4 3.0
+ O16 23.3 28.6 35.2
+ O17 34.8 17.2 12.5
+ O18 22.8 26.2 17.9
+ O19 25.2 12.8 1.5
+ P1 64.4 66.6 43.5
+ P2 20.5 28.7 46.5
+ P3 12.4 9.4 28.8
+ P4 4.5 2.6 4.6
+ P5 45.0 51.5 35.8
+ P6 60.3 69.7 4.5
+ P7 6.8 5.4 20.9
+ P8 11.9 12.3 9.9
+ P9 13.8 14.3 11.5
+ P10 15.8 16.4 13.1
+ P11 18.6 19.3 15.5
+ P12 58.6 57.7 7.1
+ P13 7.4 15.4 33.0
+ P14 23.8 23.1 33.3
+ P15 6.6 13.1 2.1
+ P16 29.5 19.6 4.5
+ P17 20.7 20.1 27.9
+ P18 47.5 30.7 9.3
+ P19 9.9 23.4 23.2
+ Q1 28.1 14.4 1.3
+ Q2 9.3 5.4 1.4
+ Q3 23.8 27.7 6.1
+ Q4 19.6 28.6 14.4
+ Q5 12.9 11.7 1.3
+ Q6 7.6 7.5 33.6
+ Q7 12.2 21.3 7.6
+ Q8 21.3 22.2 17.8
+ Q9 25.1 26.2 20.9
+ Q10 30.9 32.2 26.0
+ Q11 35.4 36.8 29.7
+ Q12 20.8 11.7 1.8
+ Q13 6.6 8.4 5.6
+ Q14 15.9 14.9 16.8
+ Q15 9.9 9.0 39.5
+ Q16 20.1 20.2 28.5
+ Q17 34.9 18.3 1.4
+ Q18 10.8 8.8 30.7
+ Q19 51.3 43.9 42.6
+ R1 1.0 1.7 1.7
+ R2 21.7 37.2 35.0
+ R3 33.0 26.0 44.3
+ R4 35.3 21.7 34.5
+ R5 63.9 61.6 52.8
+ R6 72.6 70.6 54.1
+ R7 21.6 12.2 2.0
+ R8 39.9 41.5 33.6
+ R9 45.7 47.4 38.6
+ R10 50.8 52.7 42.6
+ R11 57.2 59.4 48.2
+ R12 11.6 20.6 7.4
+ R13 15.2 26.0 26.9
+ R14 39.4 33.9 16.0
+ R15 28.3 29.3 19.2
+ R16 39.3 30.3 15.8
+ R17 60.8 49.5 52.7
+ R18 21.3 38.8 13.5
+ R19 31.4 16.1 1.2
+ S1 13.7 30.4 12.7
+ S2 39.9 21.6 27.3
+ S3 9.0 16.6 2.2
+ S4 19.2 20.0 15.7
+ S5 3.7 6.9 1.6
+ S6 44.5 25.3 29.8
+ S7 56.7 55.5 6.8
+ S8 64.0 66.5 54.2
+ S9 71.8 74.4 60.6
+ S10 80.2 83.3 67.4
+ S11 82.9 86.1 70.1
+ S12 6.6 5.2 19.6
+ S13 31.1 35.8 2.9
+ S14 29.2 18.4 8.8
+ S15 5.6 15.6 3.2
+ S16 18.4 13.3 7.0
+ S17 9.2 23.5 4.2
+ S18 54.2 43.2 2.0
+ S19 8.5 7.7 31.3
+ T1 27.1 17.2 31.4
+ T2 11.1 10.9 37.5
+ T3 32.1 16.5 1.1
+ T4 10.7 25.2 3.7
+ T5 47.7 52.9 42.7
+ T6 8.8 14.6 6.0
+ T7 31.3 19.8 22.6
+ T8 13.0 19.0 30.5
+ T9 6.8 5.4 20.8
+ T10 12.3 21.3 7.6
+ T11 21.6 12.2 2.0
+ T12 56.4 55.2 6.7
+ T13 18.3 11.9 28.5
+ T14 19.6 36.8 5.4
+ T15 38.2 21.2 1.4
+ T16 6.0 7.7 16.7
+ T17 1.7 1.4 1.1
+ T18 4.1 12.1 6.4
+ T19 12.0 28.0 6.6
+ U1 64.4 73.6 9.8
+ U2 8.7 22.6 3.9
+ U3 13.6 14.3 44.6
+ U4 13.1 29.1 19.5
+ U5 6.5 13.1 2.0
+ U6 45.7 31.7 25.9
+ U7 34.9 46.2 64.6
+ U8 11.4 26.6 4.0
+ U9 1.7 2.1 1.8
+ U10 56.0 42.9 49.4
+ U11 58.0 46.5 26.1
+ U12 33.9 17.4 1.4
+ U13 22.4 24.9 6.2
+ U14 27.5 13.9 16.1
+ U15 15.9 32.5 20.2
+ U16 33.3 17.3 1.1
+ U17 26.5 28.1 53.0
+ U18 79.1 80.2 65.2
+ U19 44.1 41.1 4.6
+ V1 5.9 13.4 14.4
+ V2 40.0 50.4 42.4
+ V3 15.1 31.8 6.4
+ V4 10.8 5.8 10.8
+ V5 59.9 52.9 31.4
+ V6 6.7 7.9 5.1
+ V7 30.6 17.9 29.5
+ V8 16.8 23.4 56.2
+ V9 35.0 26.2 13.8
+ V10 8.0 22.0 7.1
+ V11 5.4 3.4 1.1
+ V12 28.2 46.1 14.8
+ V13 14.0 7.1 5.9
+ V14 20.2 19.2 11.1
+ V15 30.1 18.6 32.1
+ V16 16.4 32.8 22.8
+ V17 57.3 43.5 12.4
+ V18 49.7 32.6 21.1
+ V19 48.7 53.0 61.0
+ W1 72.6 79.0 34.3
+ W2 8.7 6.2 2.6
+ W3 19.0 17.6 45.1
+ W4 10.3 11.7 1.5
+ W5 28.3 29.3 19.2
+ W6 45.8 26.8 33.1
+ W7 6.9 13.6 14.0
+ W8 39.7 59.2 22.8
+ W9 27.9 45.6 10.2
+ W10 0.9 1.3 1.5
+ W11 18.6 32.0 44.2
+ W12 40.9 23.6 4.4
+ W13 64.3 56.8 32.7
+ W14 67.4 72.9 4.1
+ W15 2.8 6.8 1.9
+ W16 29.9 17.3 28.7
+ W17 72.9 75.2 65.6
+ W18 4.1 9.1 9.5
+ W19 1.7 5.0 2.0
+ X1 15.8 26.4 44.2
+ X2 42.9 55.2 46.0
+ X3 22.3 11.7 1.1
+ X4 82.6 85.8 69.6
+ X5 1.4 1.2 1.0
+ X6 32.6 46.8 15.6
+ X7 31.0 34.4 7.5
+ X8 80.2 81.7 65.2
+ X9 66.8 58.4 56.3
+ X10 11.2 26.7 11.9
+ X11 29.4 29.9 54.4
+ X12 14.9 15.3 15.1
+ X13 14.6 8.4 1.0
+ X14 12.6 9.6 1.4
+ X15 56.7 63.5 44.2
+ X16 36.0 19.1 1.3
+ X17 44.9 52.8 2.8
+ X18 69.3 76.2 62.8
+ X19 63.9 73.0 7.6
+ Y1 38.6 52.7 30.2
+ Y2 16.0 19.6 8.5
+ Y3 57.3 43.4 33.4
+ Y4 26.5 22.1 5.5
+ Y5 5.7 15.8 3.3
+ Y6 58.4 46.3 51.3
+ Y7 81.7 84.3 66.0
+ Y8 14.3 11.1 1.3
+ Y9 4.4 13.9 3.1
+ Y10 64.1 60.7 8.8
+ Y11 18.0 34.1 27.2
+ Y12 34.9 18.4 1.3
+ Y13 23.5 39.2 35.9
+ Y14 45.7 47.1 44.0
+ Y15 27.1 18.6 36.9
+ Y16 12.4 28.5 7.3
+ Y17 39.4 40.7 27.4
+ Y18 3.5 9.1 2.2
+ Y19 15.1 13.9 7.7
+ Z1 28.1 23.3 15.1
+ Z2 63.2 58.8 7.8
+ Z3 4.1 11.1 2.4
+ Z4 1.1 0.9 2.9
+ Z5 73.3 79.9 64.5
+ Z6 8.6 9.0 5.5
+ Z7 7.9 7.8 33.6
+ Z8 28.8 44.3 38.3
+ Z9 31.3 16.0 1.1
+ Z10 27.4 26.5 19.1
+ Z11 2.0 1.4 8.3
+ Z12 8.5 7.7 31.5
+ Z13 15.6 18.1 1.7
+ Z14 18.3 34.1 3.7
+ Z15 2.0 2.1 0.9
+ Z16 33.5 24.8 41.9
+ Z17 6.7 3.4 6.7
+ Z18 63.8 57.5 14.1
+ Z19 78.3 82.8 66.9
+ 2A1 0.9 1.1 0.9
+ 2A2 19.6 13.8 5.9
+ 2A3 38.7 21.2 9.9
+ 2A4 12.4 28.7 8.0
+ 2A5 10.2 9.9 16.8
+ 2A6 47.3 32.1 42.4
+ 2A7 8.5 22.3 3.9
+ 2A8 1.7 2.9 1.4
+ 2A9 14.3 10.1 27.8
+ 2A10 24.7 15.1 1.3
+ 2A11 40.4 55.4 48.2
+ 2A12 12.5 28.6 6.6
+ 2A13 17.0 12.5 15.7
+ 2A14 14.6 16.9 11.6
+ 2A15 35.4 36.8 29.1
+ 2A16 11.2 14.4 7.2
+ 2A17 8.1 22.0 12.6
+ 2A18 14.7 14.8 43.4
+ 2A19 52.6 34.1 36.1
+ 2B1 8.2 21.5 3.7
+ 2B2 40.1 55.9 5.0
+ 2B3 8.5 8.6 35.2
+ 2B4 23.3 16.1 34.6
+ 2B5 66.3 74.2 52.1
+ 2B6 66.5 70.5 66.1
+ 2B7 7.9 7.3 31.5
+ 2B8 23.4 40.5 20.0
+ 2B9 53.1 55.4 36.6
+ 2B10 23.4 30.2 26.5
+ 2B11 7.7 20.8 3.7
+ 2B12 13.5 11.6 32.2
+ 2B13 65.4 74.1 61.6
+ 2B14 34.7 21.0 33.0
+ 2B15 32.4 16.3 4.5
+ 2B16 44.5 39.0 18.5
+ 2B17 39.8 22.5 5.0
+ 2B18 45.2 26.2 19.4
+ 2B19 7.2 7.7 35.3
+ 2C1 42.8 48.7 62.0
+ 2C2 2.4 5.9 1.8
+ 2C3 20.1 26.5 5.2
+ 2C4 13.8 30.3 9.9
+ 2C5 12.2 9.3 29.9
+ 2C6 23.7 15.2 31.0
+ 2C7 21.9 39.4 13.3
+ 2C8 67.5 58.5 45.1
+ 2C9 20.1 13.5 30.7
+ 2C10 14.3 7.0 6.2
+ 2C11 45.5 59.1 51.0
+ 2C12 71.1 79.0 57.3
+ 2C13 7.1 7.8 36.9
+ 2C14 81.9 84.9 66.1
+ 2C15 7.1 6.1 27.2
+ 2C16 2.8 1.8 12.5
+ 2C17 7.6 8.6 1.2
+ 2C18 13.3 16.4 27.7
+ 2C19 59.2 68.5 4.0
+ 2D1 24.7 15.9 35.5
+ 2D2 27.6 17.5 15.1
+ 2D3 10.0 8.5 31.6
+ 2D4 1.8 2.0 6.8
+ 2D5 7.6 20.5 3.8
+ 2D6 1.3 1.6 1.1
+ 2D7 67.9 74.5 4.7
+ 2D8 37.8 40.3 56.9
+ 2D9 21.7 29.5 9.7
+ 2D10 24.5 27.3 22.3
+ 2D11 8.6 7.3 3.6
+ 2D12 8.1 11.8 14.9
+ 2D13 14.5 7.6 2.0
+ 2D14 17.5 13.6 35.9
+ 2D15 26.0 16.5 1.2
+ 2D16 37.5 20.6 5.1
+ 2D17 76.8 74.9 62.0
+ 2D18 73.7 79.1 41.9
+ 2D19 42.6 25.1 4.4
diff --git a/ref/ColorCheckerSG.ti2 b/ref/ColorCheckerSG.ti2
index 7459061..239b9e6 100644
--- a/ref/ColorCheckerSG.ti2
+++ b/ref/ColorCheckerSG.ti2
@@ -1,284 +1,163 @@
-CTI3
+CTI2
-DESCRIPTOR "Argyll Calibration Target chart information 3"
-ORIGINATOR "Argyll target"
-CREATED "Thu Feb 04 12:14:29 2010"
-KEYWORD "DEVICE_CLASS"
-DEVICE_CLASS "INPUT"
-KEYWORD "COLOR_REP"
-COLOR_REP "XYZ_RGB"
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+ORIGINATOR "Argyll printtarg"
+CREATED "Mon Feb 10 15:05:27 2014"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
-KEYWORD "STDEV_R"
-KEYWORD "STDEV_G"
-NUMBER_OF_FIELDS 10
+COLOR_REP "RGB"
+STEPS_IN_PASS 10
+PASSES_IN_STRIPS2 14
+STRIP_INDEX_PATTERN "A-Z, A-Z"
+PATCH_INDEX_PATTERN "@-9,0-9;01-99"
+INDEX_ORDER "STRIP_THEN_PATCH"
+
+NUMBER_OF_FIELDS 8
BEGIN_DATA_FORMAT
-SAMPLE_ID XYZ_X XYZ_Y XYZ_Z RGB_R RGB_G RGB_B STDEV_R STDEV_G STDEV_B
+SAMPLE_ID SAMPLE_LOC XYZ_X XYZ_Y XYZ_Z RGB_R RGB_G RGB_B
END_DATA_FORMAT
-NUMBER_OF_SETS 264
+NUMBER_OF_SETS 140
BEGIN_DATA
-A01 3.8500 3.2200 1.9000 3.0870 1.9150 1.9568 0.18288 0.33530 0.13814
-A02 4.8900 3.2700 1.6000 4.3780 1.1194 1.5620 0.18986 0.21677 0.15053
-A03 5.8700 3.3100 1.3300 7.0969 0.79829 1.4596 0.19608 0.13702 0.21648
-A04 6.3000 3.3800 1.1900 9.3444 0.79154 1.6415 0.24898 0.11159 0.21239
-A05 13.010 11.440 7.6400 14.232 7.8664 9.0240 0.51082 0.34461 0.40609
-A06 16.140 11.990 6.8100 19.112 4.9827 7.4008 0.27379 0.27636 0.24485
-A07 19.350 12.410 6.0600 24.550 2.9139 6.6589 0.44040 0.23921 0.36013
-A08 20.410 11.970 5.3000 28.200 1.9757 5.6575 0.32681 0.17783 0.34406
-A09 43.500 42.810 32.650 50.412 41.562 43.136 0.83769 0.58646 0.66130
-A10 45.580 42.370 30.950 52.491 37.167 40.121 0.65668 0.68089 0.75167
-A11 48.990 43.200 29.900 55.546 34.358 38.456 0.89084 0.72144 0.46689
-A12 50.730 44.020 29.960 59.252 33.923 39.172 0.67792 0.64492 0.71595
-A13 74.460 78.760 66.060 86.999 87.136 83.095 0.84067 0.78370 1.0173
-A14 75.660 76.420 64.080 88.257 85.809 81.940 0.97591 0.87575 0.93144
-A15 78.360 81.340 65.410 89.349 87.424 79.630 0.80575 0.84750 0.90746
-A16 70.520 73.300 59.160 83.248 81.172 76.884 0.59765 0.53177 0.91515
-A17 74.980 75.980 60.690 86.615 83.456 77.766 0.59041 0.64935 0.85237
-A18 72.850 77.300 60.250 85.072 85.370 78.761 0.67171 0.77803 0.78435
-A19 73.090 75.520 64.540 85.077 84.325 81.725 0.60827 0.53488 0.74148
-B01 3.4700 3.0800 1.4100 2.9819 1.8666 1.5474 0.25109 0.26023 0.14749
-B02 4.4100 3.2500 0.90000 3.9091 1.1519 0.44191 0.19422 0.17547 0.17939
-B03 5.0400 3.2300 0.58000 5.7842 0.78053 0.49340 0.39093 0.14767 0.25096
-B04 5.1900 3.1100 0.47000 6.2788 0.70721 0.41772 0.082907 0.18786 0.25207
-B05 13.360 11.590 5.5600 14.926 7.8469 6.2059 0.44744 0.41222 0.43440
-B06 15.970 12.030 3.6900 19.562 5.8030 4.2553 0.47005 0.19252 0.20287
-B07 19.200 12.490 2.2000 25.891 4.1954 2.6920 0.33271 0.22817 0.18918
-B08 19.730 11.520 1.1700 29.809 2.8266 1.9401 0.23472 0.24036 0.14395
-B09 42.190 41.840 29.340 52.125 42.714 40.345 0.71433 0.70374 0.66837
-B10 44.830 42.170 25.930 54.839 39.132 35.238 0.62084 0.61210 0.58037
-B11 48.060 42.900 23.010 60.127 37.706 33.524 0.63887 0.38462 0.62824
-B12 49.630 43.080 21.340 63.922 37.324 32.146 0.65762 0.54522 0.68989
-B13 66.210 72.540 64.610 81.667 84.767 81.706 0.65741 0.59295 0.68550
-B14 70.160 67.100 60.330 84.214 77.614 79.176 0.57243 0.69736 0.83505
-B15 75.460 78.690 51.580 87.872 84.913 72.334 0.64511 0.86763 0.77954
-B16 57.470 59.580 47.660 65.637 62.374 61.374 0.46048 0.54234 0.88766
-B17 68.330 66.450 49.050 80.849 69.402 66.741 0.47062 0.59840 0.78706
-B18 63.890 70.290 51.300 75.219 79.157 68.777 0.46400 0.45401 0.74257
-B19 61.120 62.160 59.790 74.928 72.212 78.002 0.52358 0.56321 0.65812
-C01 4.9700 4.7500 1.9800 3.8530 2.8861 1.9553 0.22700 0.21393 0.14122
-C02 5.1800 4.6500 1.2300 4.3282 2.3874 0.79270 0.23735 0.24096 0.13415
-C03 5.5100 4.5800 0.71000 4.8509 1.9934 0.37347 0.30081 0.24896 0.16563
-C04 5.7700 4.6100 0.67000 5.4652 2.2904 0.39892 0.31940 0.40663 0.17898
-C05 24.570 23.440 10.140 29.971 21.188 14.074 0.87441 0.65043 0.60853
-C06 28.100 24.640 5.2200 35.224 19.484 6.2233 0.47051 0.51996 0.34475
-C07 31.150 25.280 2.2000 43.555 21.569 1.7662 0.53328 0.28476 0.22826
-C08 30.850 23.680 1.3500 47.906 23.705 0.73860 0.48852 0.54401 0.30082
-C09 49.160 49.360 32.370 61.372 52.131 41.915 1.0230 0.96228 0.93947
-C10 51.720 50.720 26.530 66.081 50.197 35.277 0.52582 0.59072 0.68577
-C11 55.240 53.140 21.930 73.019 53.527 32.275 0.44506 0.61523 0.51984
-C12 56.870 53.620 18.460 76.306 55.256 27.858 0.73837 0.62107 0.67223
-C13 57.680 65.650 62.700 69.094 79.718 80.057 0.50745 0.49506 0.65851
-C14 63.460 56.660 55.490 79.979 64.212 75.539 0.48047 0.70668 0.61269
-C15 73.000 76.110 40.780 87.834 83.405 60.764 0.46451 0.49319 0.94645
-C16 44.730 46.380 36.800 49.238 47.428 48.251 0.66946 0.56694 0.71058
-C17 60.640 55.730 38.100 77.490 58.018 53.328 0.50391 0.73108 0.76100
-C18 52.150 60.270 41.500 59.790 70.951 55.734 0.51624 0.54134 0.69219
-C19 48.130 49.180 54.380 55.359 55.873 71.348 0.69989 0.65714 0.84068
-D01 4.1900 4.4100 1.9300 3.1562 3.1899 2.0240 0.14406 0.17903 0.20820
-D02 4.4800 4.7200 1.2400 3.1439 3.1237 0.90907 0.22921 0.19312 0.19845
-D03 4.5500 4.7800 0.80000 3.1884 3.4386 0.76835 0.18973 0.19251 0.14068
-D04 4.3200 4.5300 0.78000 2.7510 3.7222 0.39598 0.089835 0.21097 0.093653
-D05 27.330 28.550 12.950 32.935 30.788 16.103 0.86272 0.76614 1.0290
-D06 28.680 30.040 7.2500 34.121 32.521 9.2587 0.39709 0.61832 0.39734
-D07 29.510 31.010 3.4100 36.086 34.806 2.1211 0.45752 0.42772 0.32549
-D08 27.550 28.440 1.8300 37.395 33.673 0.41712 0.48746 0.39838 0.24261
-D09 56.060 58.190 38.210 68.806 62.355 48.849 0.83407 1.0243 1.0103
-D10 56.030 58.460 30.020 69.259 58.718 33.748 0.64690 0.51168 0.69310
-D11 56.200 59.330 24.440 73.375 62.236 30.616 0.61702 0.52252 0.65243
-D12 56.190 59.410 19.140 77.878 67.860 28.599 0.75670 0.62150 0.58932
-D13 48.210 57.420 59.530 51.811 71.459 76.862 0.52665 0.65682 0.77453
-D14 58.180 49.140 51.360 72.528 46.885 68.418 0.52499 0.49346 0.72705
-D15 70.980 73.730 33.630 87.340 80.456 47.511 0.58420 0.59197 0.74605
-D16 34.310 35.730 28.220 36.385 34.641 36.216 0.65565 0.55419 0.71008
-D17 54.270 47.530 29.580 71.607 44.334 41.932 0.46944 0.43555 0.66646
-D18 41.670 50.640 32.280 40.678 55.829 39.983 0.43992 0.47148 0.62583
-D19 36.950 37.820 48.090 37.649 36.082 58.334 0.42908 0.54659 0.83641
-E01 4.1500 4.7500 2.0300 3.1080 3.5881 2.3054 0.15860 0.18960 0.21718
-E02 4.0000 4.9800 1.3700 2.2371 3.5825 0.94616 0.25476 0.27294 0.19591
-E03 3.3000 4.4900 0.86000 1.6523 4.0563 0.38062 0.19385 0.38560 0.11779
-E04 3.1100 4.3000 0.86000 1.5621 5.4761 0.39158 0.26069 0.52827 0.12416
-E05 13.110 14.900 7.0600 15.304 17.657 10.409 0.47522 0.71252 0.51942
-E06 12.260 15.230 4.1800 12.178 18.905 5.5227 0.25140 0.45664 0.32497
-E07 11.530 15.570 2.2700 11.698 21.930 1.9527 0.26015 0.27007 0.21988
-E08 9.6900 13.740 1.5100 10.276 19.833 0.79976 0.39423 0.37372 0.23614
-E09 39.150 42.080 27.330 45.518 46.666 38.440 0.69913 0.70519 0.71247
-E10 37.430 41.510 22.230 44.807 49.208 32.547 0.55033 0.61108 0.60908
-E11 36.990 42.500 18.850 43.914 51.799 27.847 0.33881 0.53443 0.59872
-E12 36.400 42.580 16.270 43.530 52.579 24.028 0.42317 0.40277 0.79064
-E13 39.970 49.810 56.150 39.429 62.735 72.585 0.51788 0.70956 0.61542
-E14 52.080 41.070 46.360 60.752 30.200 56.615 0.61389 0.53882 0.50726
-E15 68.710 70.760 26.450 86.100 76.861 38.303 0.41619 0.79801 0.68629
-E16 25.700 26.970 21.280 27.203 25.514 27.365 0.37071 0.36979 0.64204
-E17 48.530 40.600 22.000 63.064 33.698 32.716 0.65833 0.49787 0.51247
-E18 31.620 40.820 23.350 33.628 51.020 34.670 0.45510 0.54658 0.59089
-E19 31.190 31.190 43.400 29.013 27.025 51.220 0.47563 0.55117 0.57962
-F01 1.5100 1.9100 1.0600 0.027596 0.75636 0.74985 0.15629 0.19236 0.22766
-F02 1.2900 2.0400 0.98000 4.9390e-004 1.0482 0.39366 0.027695 0.20025 0.047727
-F03 1.1600 2.0900 0.82000 1.2211e-003 1.3702 0.39338 0.055216 0.20402 0.055216
-F04 1.1400 2.0400 0.80000 5.2010e-004 1.8140 0.39216 0.028412 0.19742 8.7191e-017
-F05 6.5300 8.2500 5.1300 6.0620 8.7613 6.3749 0.21856 0.39993 0.34077
-F06 5.6100 8.6600 4.3800 5.0928 12.540 5.5351 0.32257 0.22932 0.31753
-F07 4.6000 8.7700 3.7000 3.9791 14.933 5.5371 0.22839 0.40306 0.31189
-F08 3.4500 7.6300 2.7800 3.1943 13.637 5.0607 0.18371 0.31217 0.28611
-F09 37.800 41.070 30.910 42.311 46.542 44.099 0.66414 0.71461 0.48054
-F10 35.920 40.760 29.030 37.090 45.514 41.038 0.54192 0.47361 0.49637
-F11 35.420 41.990 29.070 33.769 46.586 39.188 0.63863 0.44377 0.74150
-F12 34.000 41.800 28.000 32.661 47.456 39.230 0.38028 0.53728 0.61597
-F13 32.130 42.120 51.990 33.383 57.669 70.984 0.45695 0.68345 0.74883
-F14 45.720 33.340 40.770 54.515 21.176 49.435 0.62848 0.60201 0.59089
-F15 66.260 67.290 19.650 85.509 74.348 30.963 0.34004 0.66164 0.72944
-F16 17.020 18.070 14.400 18.492 17.628 19.716 0.41175 0.41125 0.55653
-F17 41.590 32.530 15.160 55.337 23.031 22.717 0.32869 0.58391 0.55775
-F18 26.260 35.260 18.810 29.664 47.253 28.577 0.65266 0.49301 0.47012
-F19 24.300 23.600 37.480 19.299 17.238 43.015 0.51151 0.45280 0.37522
-G01 2.3100 3.0000 2.2700 0.84520 2.3174 1.9294 0.18283 0.18185 0.16146
-G02 2.0000 3.2100 2.5800 0.75456 2.8979 2.5428 0.15935 0.25240 0.20833
-G03 1.6600 3.2100 2.7500 0.76882 3.1767 2.7895 0.13653 0.18762 0.18509
-G04 1.5800 3.0300 2.6000 0.72753 3.5401 3.1385 0.21153 0.23805 0.12733
-G05 8.9900 11.080 8.7900 8.6417 12.633 13.013 0.23258 0.38272 0.51760
-G06 7.6800 11.300 9.5600 6.0762 14.162 13.630 0.34219 0.48961 0.37830
-G07 6.5200 11.500 10.200 4.7151 15.595 15.675 0.18999 0.25121 0.34355
-G08 5.5000 10.850 10.550 3.9310 15.708 18.487 0.17658 0.18808 0.38867
-G09 38.290 41.750 33.450 41.221 46.682 47.377 0.47434 0.65583 0.69760
-G10 35.830 41.160 34.110 34.960 46.653 48.630 0.43230 0.33577 0.68757
-G11 34.560 41.830 35.630 33.586 49.866 51.379 0.54290 0.54558 0.79591
-G12 33.690 42.140 36.700 33.047 50.497 52.510 0.47475 0.63324 0.64506
-G13 25.950 35.680 48.000 25.821 49.453 66.662 0.37812 0.43551 0.68026
-G14 40.600 27.620 36.140 49.315 12.855 43.923 0.59407 0.51249 0.39980
-G15 63.720 63.630 14.350 85.087 71.090 23.531 0.42910 0.70922 0.51323
-G16 10.850 11.820 9.5800 12.480 12.126 12.956 0.45159 0.26832 0.47760
-G17 37.230 27.640 11.620 47.527 14.544 15.337 0.27575 0.21502 0.45406
-G18 20.280 28.970 14.150 22.086 39.214 21.499 0.22375 0.42080 0.58054
-G19 17.700 16.740 31.700 11.092 8.9799 34.605 0.30961 0.25432 0.34654
-H01 2.5600 3.0400 2.9200 1.0797 1.6510 2.5225 0.19148 0.29249 0.31180
-H02 2.3400 3.2000 4.1200 0.75605 1.9921 3.9184 0.20879 0.18831 0.34399
-H03 2.1200 3.2800 5.4300 1.1188 2.6942 5.7632 0.18331 0.31552 0.43690
-H04 2.0600 3.1800 5.2900 0.95250 3.6569 9.1081 0.19606 0.26991 0.32976
-H05 10.070 11.600 11.240 8.3322 11.376 15.622 0.28376 0.42701 0.40381
-H06 9.0100 11.680 14.810 5.4932 11.765 20.056 0.091608 0.41488 0.57575
-H07 8.2200 12.000 19.420 4.9770 14.064 28.422 0.20715 0.32326 0.42487
-H08 7.2500 11.550 21.450 3.2684 15.675 34.112 0.21933 0.26892 0.44285
-H09 39.250 42.310 36.810 41.417 46.807 52.636 0.40783 0.63180 0.70186
-H10 37.580 41.850 40.370 37.620 47.457 56.394 0.40780 0.38262 0.60753
-H11 37.160 43.070 45.790 35.702 50.905 63.199 0.32421 0.46580 0.63305
-H12 36.270 43.780 49.470 33.495 51.722 65.912 0.49238 0.80083 0.50501
-H13 21.470 30.780 44.220 17.358 41.175 60.322 0.53191 0.33884 0.71172
-H14 36.490 23.350 32.380 42.559 7.4512 37.794 0.63662 0.37435 0.45301
-H15 61.580 60.550 10.950 83.946 67.032 17.125 0.47747 0.68565 0.68924
-H16 8.2100 8.7100 6.9100 7.7370 6.7073 7.1914 0.30311 0.32664 0.38434
-H17 33.040 23.260 8.3800 41.945 9.7770 9.4041 0.36608 0.27977 0.29341
-H18 16.220 24.350 10.410 14.161 31.400 14.036 0.50870 0.42853 0.33315
-H19 12.860 11.840 26.820 6.7641 4.8816 27.846 0.21234 0.35512 0.43660
-I01 4.2200 4.4400 5.2800 2.5804 3.1209 5.5388 0.19793 0.22097 0.23814
-I02 4.3500 4.4800 8.3600 2.1950 2.9540 8.2511 0.21318 0.37273 0.15204
-I03 4.4000 4.4400 11.940 1.5551 2.3277 13.781 0.13059 0.32101 0.44139
-I04 4.4800 4.5800 12.170 1.5183 2.7011 16.873 0.18903 0.18775 0.54146
-I05 15.150 15.780 15.230 14.098 13.280 19.482 0.38631 0.35696 0.61921
-I06 14.560 15.120 19.520 11.398 11.740 26.460 0.39190 0.31696 0.53900
-I07 14.370 14.810 24.480 9.0951 10.558 31.378 0.31653 0.47750 0.40616
-I08 14.110 14.760 30.030 8.8994 12.525 38.791 0.19577 0.41303 0.47520
-I09 41.030 42.580 36.940 44.643 44.074 50.860 0.49120 0.38131 0.77241
-I10 40.850 42.230 40.730 43.872 44.287 55.517 0.47835 0.37431 0.74007
-I11 40.860 42.330 45.050 42.122 43.554 59.117 0.48773 0.61376 0.75436
-I12 41.310 42.730 47.770 40.877 43.038 60.455 0.52027 0.78243 0.89880
-I13 17.260 25.930 40.230 11.385 33.626 53.134 0.24543 0.46746 0.49207
-I14 32.660 19.630 28.810 37.259 3.1300 31.648 0.53636 0.22763 0.56347
-I15 59.370 57.180 7.7900 81.619 61.582 10.428 0.45678 0.75637 0.50761
-I16 4.9700 5.3200 4.3200 4.1247 4.2743 4.4333 0.25062 0.28647 0.22229
-I17 28.620 18.880 5.4800 37.742 6.2496 5.7060 0.30537 0.26137 0.31918
-I18 11.580 18.980 7.2500 10.598 26.684 8.8664 0.26978 0.44054 0.42495
-I19 9.5800 8.3400 22.870 4.2150 3.2891 23.893 0.21095 0.25111 0.44678
-I20 0.45000 0.40000 0.33000 0.39216 0.39216 0.54897 8.7185e-017 8.7185e-017 0.19577
-I21 2.2800 1.7800 0.98000 1.5621 0.40380 0.78485 0.17869 0.12419 0.10123
-I22 2.3700 1.9500 0.85000 1.6757 0.52953 0.77981 0.20785 0.19502 0.097289
-J01 2.1500 1.9000 2.6000 0.80586 0.46230 2.3504 0.14574 0.18600 0.061302
-J02 2.5700 2.0000 4.7200 0.88254 0.50462 3.8319 0.23987 0.27408 0.28547
-J03 2.9300 1.9500 8.1000 1.1741 0.79211 7.0759 0.059711 0.10088 0.41081
-J04 3.1500 1.9200 10.760 1.1579 0.78634 9.8197 0.13923 0.054971 0.30540
-J05 11.730 11.600 11.810 10.434 9.0014 15.080 0.27064 0.18087 0.39725
-J06 12.980 11.930 16.190 9.8203 6.5823 18.989 0.42140 0.31577 0.43052
-J07 13.910 12.070 20.950 9.0486 5.3905 24.287 0.43191 0.32612 0.46685
-J08 14.010 11.590 24.350 9.4663 4.4573 26.676 0.46513 0.26033 0.44412
-J09 40.750 41.220 36.340 46.279 42.745 50.219 0.48484 0.49432 0.71791
-J10 41.260 41.070 39.740 46.208 41.530 53.967 0.39057 0.37860 0.69962
-J11 42.630 41.680 44.510 46.276 39.907 57.241 0.36909 0.43099 0.77240
-J12 44.020 41.780 49.250 46.523 38.842 60.774 0.60050 0.54935 0.80146
-J13 13.820 21.690 35.980 6.4384 27.059 47.284 0.27804 0.44682 0.53798
-J14 28.870 16.330 25.080 33.360 1.4880 26.700 0.54686 0.35986 0.50147
-J15 56.040 52.290 4.9700 79.215 55.635 5.6027 0.36036 0.67586 0.40739
-J16 2.4600 2.6300 2.2900 2.0271 1.9425 2.1126 0.22979 0.25009 0.22276
-J17 24.040 14.750 3.1500 32.513 3.3788 3.9462 0.38941 0.25099 0.22979
-J18 8.1200 14.490 4.5500 6.8312 20.787 5.0280 0.26878 0.48921 0.37476
-J19 5.9800 4.7900 17.760 1.9349 1.4360 18.258 0.25534 0.19476 0.43841
-J20 8.2600 5.3700 1.0400 9.0085 1.2119 1.6117 0.45009 0.24630 0.21888
-J21 11.520 7.8100 1.6200 15.322 3.1307 1.6660 0.28794 0.15307 0.22993
-J22 14.670 10.720 2.6000 19.118 4.7445 3.3211 0.27061 0.23207 0.23572
-K01 5.6300 4.7000 4.8600 3.1669 2.3147 4.3372 0.16578 0.17296 0.16002
-K02 6.7400 4.5800 7.2300 4.7712 1.7242 5.8628 0.19822 0.36800 0.19901
-K03 8.0400 4.4800 9.7300 7.0830 0.83482 8.6422 0.34393 0.17784 0.40049
-K04 9.3900 4.7600 11.790 9.3140 0.83699 11.430 0.19932 0.17903 0.39652
-K05 16.660 15.390 14.440 15.838 10.461 17.251 0.32001 0.40528 0.46694
-K06 18.720 15.180 18.230 18.124 6.6879 21.403 0.40410 0.17228 0.49710
-K07 21.560 15.500 22.970 21.965 5.3109 25.015 0.24740 0.23832 0.38336
-K08 23.000 15.020 25.370 24.105 3.1608 26.801 0.32492 0.16608 0.48978
-K09 42.500 42.020 36.050 47.117 40.740 49.022 0.53629 0.37845 0.70340
-K10 44.550 41.630 39.710 49.817 36.865 51.366 0.65172 0.52763 0.69630
-K11 47.190 41.960 44.030 49.582 31.706 51.769 0.59677 0.49442 0.61865
-K12 49.900 43.140 47.210 49.812 27.011 52.296 0.66045 0.55640 0.61863
-K13 10.610 17.440 31.240 4.4300 21.053 41.922 0.22576 0.30726 0.65920
-K14 24.840 13.190 21.000 29.807 0.40689 21.925 0.51521 0.12873 0.23282
-K15 53.120 48.050 3.1900 76.497 50.546 1.9742 0.42392 0.89083 0.22911
-K16 1.0500 1.1400 1.1300 0.37611 0.38958 0.78350 0.16012 0.11365 0.056938
-K17 19.930 11.340 1.6700 28.212 1.8825 1.9270 0.20132 0.19250 0.18652
-K18 5.3000 10.470 2.7300 4.6984 16.487 2.7171 0.27557 0.20947 0.35113
-K19 3.9500 2.7600 13.940 1.1640 0.78992 13.028 0.14201 0.087689 0.38375
-K20 30.610 26.430 11.040 37.280 17.799 14.056 0.42873 0.33930 0.49948
-K21 34.910 29.600 11.780 46.591 23.876 16.346 0.59613 0.61207 0.58881
-K22 38.950 34.570 18.400 50.441 29.451 25.122 0.41109 0.46425 0.53273
-L01 3.8800 3.1200 2.3200 2.3754 1.1903 2.4650 0.23374 0.24751 0.21411
-L02 4.9300 3.2000 2.6900 3.5670 0.87669 2.4249 0.19064 0.19083 0.21057
-L03 5.7500 3.1400 3.0200 6.2627 0.88805 2.7596 0.15419 0.19237 0.13238
-L04 7.3100 3.7900 3.4000 12.143 0.79340 5.0822 0.36514 0.10735 0.18096
-L05 13.290 11.540 9.3900 13.257 6.7371 11.007 0.53413 0.39748 0.52457
-L06 16.220 11.730 10.320 17.565 4.3606 11.749 0.41329 0.23326 0.22842
-L07 19.950 12.080 12.060 23.621 1.9646 12.957 0.36857 0.073970 0.44540
-L08 20.790 11.310 12.010 27.319 1.1467 14.145 0.39539 0.24605 0.48567
-L09 43.220 42.090 33.780 49.604 40.742 46.106 0.73537 0.46689 0.65281
-L10 45.520 41.880 34.650 52.432 36.546 46.285 0.70127 0.47543 0.81335
-L11 49.040 42.870 35.980 52.918 31.732 45.276 0.56655 0.49649 0.63589
-L12 51.030 43.830 37.780 56.056 30.451 46.847 0.71159 0.54349 0.47579
-L13 7.4500 12.770 25.590 3.1210 15.741 36.868 0.16774 0.41923 0.54315
-L14 21.260 10.760 17.730 25.639 0.67463 17.297 0.33435 0.23099 0.28299
-L15 49.450 43.120 2.1400 71.709 42.401 0.77056 0.63981 0.77745 0.15935
-L16 0.47000 0.49000 0.50000 0.39216 0.39242 0.44227 8.7191e-017 0.020117 0.17760
-L17 16.040 8.4900 0.78000 22.615 0.77695 0.80931 0.41597 0.098510 0.17603
-L18 2.9100 6.5000 1.3900 2.3795 10.578 0.82736 0.41720 0.36726 0.25065
-L19 2.5000 1.4500 10.280 0.87774 0.87456 9.0192 0.19100 0.19050 0.23749
-L20 38.700 33.980 20.860 46.392 26.795 27.748 0.70761 0.62342 0.62702
-L21 39.360 35.230 21.230 49.082 30.312 29.444 0.78808 0.53733 0.63082
-L22 41.360 38.770 23.510 49.490 34.663 31.428 0.65330 0.41753 0.60905
-GS00 79.470 82.510 69.040 94.066 92.950 89.438 0.92099 0.93414 1.0465
-GS01 72.620 74.940 59.170 83.147 81.219 77.715 0.78271 0.68705 0.94766
-GS02 63.150 65.110 51.570 72.917 70.218 68.669 1.6258 1.2707 1.2120
-GS03 54.720 56.510 45.030 62.183 59.826 59.273 1.1706 0.93329 0.94511
-GS04 48.100 49.810 39.240 54.449 52.983 53.093 0.94040 0.74898 0.81106
-GS05 42.220 43.640 34.450 46.328 44.248 45.944 0.67400 0.50032 0.83337
-GS06 37.330 38.700 30.500 38.317 37.642 39.414 0.73797 0.55911 0.80063
-GS07 32.380 33.610 26.110 33.430 32.555 34.311 0.65078 0.68590 0.53545
-GS08 27.560 28.700 22.110 28.329 27.391 29.319 0.58496 0.47730 0.62283
-GS09 22.500 23.400 17.990 24.816 23.504 25.107 0.34653 0.55560 0.46821
-GS10 18.770 19.550 14.830 19.965 19.162 21.933 0.53943 0.57276 0.50639
-GS11 15.480 16.080 12.040 16.404 15.001 17.243 0.45210 0.41568 0.49656
-GS12 12.690 13.290 9.9800 12.196 12.177 13.695 0.44316 0.26670 0.48288
-GS13 10.350 10.810 7.9700 9.2053 9.3069 10.577 0.20471 0.20663 0.38564
-GS14 8.3900 8.7700 6.3700 6.8434 6.6000 6.6948 0.44020 0.30795 0.33660
-GS15 6.4500 6.7900 4.9700 5.0530 5.1099 5.4164 0.19533 0.41922 0.22533
-GS16 4.9500 5.1800 3.7000 3.5418 3.5969 4.0009 0.21349 0.20376 0.24671
-GS17 3.5800 3.8200 2.7600 2.2466 2.3553 2.3640 0.20655 0.13937 0.14287
-GS18 2.7600 2.8900 2.0600 1.1077 1.1790 1.5754 0.28160 0.25904 0.24353
-GS19 1.9700 2.0800 1.4500 0.35943 0.40395 0.79579 0.18424 0.11867 0.11747
-GS20 1.2200 1.3100 0.98000 0.23507 0.31297 0.70239 0.19729 0.21133 0.18880
-GS21 1.0000 1.0500 0.74000 0.38400 0.38523 0.77548 0.10266 0.10537 0.10605
-GS22 0.87000 0.89000 0.65000 0.39216 0.39216 0.74886 8.7126e-017 8.7126e-017 0.16598
-GS23 0.34000 0.32000 0.32000 0.39226 0.39237 0.43006 0.012929 0.018274 0.16840
+1 "A01" 88.2480 87.5060 67.6240 99.2353 99.7118 99.5554
+2 "A02" 0.794510 0.785690 0.624230 3.14714 4.68603 5.08608
+3 "A03" 18.3810 18.1460 14.1200 54.0301 65.6038 60.7520
+4 "A04" 88.6800 87.9440 68.0980 99.0451 99.4536 99.2556
+5 "A05" 0.824100 0.810630 0.656110 3.10665 4.43021 4.90322
+6 "A06" 18.4400 18.2040 14.1760 52.4803 64.1539 59.5981
+7 "A07" 88.6450 87.9000 67.9470 98.8924 98.9556 99.1026
+8 "A08" 0.832010 0.821550 0.664060 3.16261 3.84029 4.35848
+9 "A09" 18.1170 17.8910 13.9510 49.3671 61.6291 56.5615
+10 "A10" 88.8710 88.1260 68.0820 98.6642 99.1385 99.0660
+11 "B01" 18.0200 17.7950 13.9090 55.0686 66.0592 61.9429
+12 "B02" 13.9470 7.22560 8.26540 68.1681 0.0450395 56.4805
+13 "B03" 35.6280 27.8520 32.8420 88.8315 59.9937 99.6552
+14 "B04" 10.6720 5.28080 15.2480 43.1040 0.0502000 87.5639
+15 "B05" 14.4130 15.7890 39.3970 21.7750 70.1273 99.9547
+16 "B06" 20.6780 26.2380 36.8920 35.2551 99.0188 77.5504
+17 "B07" 1.45030 2.34850 2.56120 2.04420 12.9928 18.2739
+18 "B08" 18.0380 25.7190 27.0400 32.3543 99.9619 64.7212
+19 "B09" 3.37980 3.27430 1.57890 8.38116 9.89768 6.55200
+20 "B10" 18.4840 18.2440 14.1910 51.0152 63.0221 58.4410
+21 "C01" 0.825050 0.814760 0.657280 3.45013 5.01294 5.40847
+22 "C02" 4.57810 3.29160 5.61620 12.9428 4.08519 38.0010
+23 "C03" 14.5950 11.3080 24.2900 43.8628 27.8035 99.9476
+24 "C04" 2.74320 2.49490 8.91480 0.0841099 5.05299 57.3589
+25 "C05" 22.9170 25.7880 40.2490 47.8425 89.5040 94.9187
+26 "C06" 1.83670 2.40490 5.02520 0.0925296 8.61708 42.0348
+26 "C07" 26.4450 26.6910 42.3540 60.2448 80.4263 99.6501
+28 "C08" 10.2540 16.9170 17.2820 20.7339 88.7631 52.2998
+29 "C09" 19.0520 27.2060 12.2700 41.1843 99.8507 35.2397
+30 "C10" 0.805310 0.795850 0.639850 3.03575 4.08577 4.67877
+31 "D01" 88.4950 87.7520 67.9080 99.5510 99.5464 99.5571
+32 "D02" 61.9490 61.4510 55.8040 96.4784 96.5058 99.5547
+33 "D03" 70.8290 63.5300 49.3270 99.7724 92.6467 98.0025
+34 "D04" 55.9600 62.6940 49.9140 89.0089 99.9676 94.1003
+35 "D05" 71.1690 64.5570 44.5670 99.8200 93.1762 96.0933
+36 "D06" 58.4250 62.2180 28.8560 95.2652 97.4714 85.5067
+37 "D07" 38.5680 30.1250 8.72090 97.7247 60.9183 25.4159
+38 "D08" 38.9330 32.3110 15.6350 94.9899 67.4615 67.8546
+39 "D09" 9.70690 17.2520 8.69020 18.0329 94.3103 15.6986
+40 "D10" 88.8520 88.1030 68.1490 98.8895 98.9418 99.0172
+41 "E01" 18.1400 17.9140 13.9700 56.1278 67.1050 63.4896
+42 "E02" 8.91530 6.95450 2.01090 42.6753 18.3928 0.240737
+43 "E03" 39.6620 29.4150 2.05650 99.8589 57.9921 0.763152
+44 "E04" 3.84910 2.21640 16.3130 0.0356264 1.61558 77.2429
+45 "E05" 88.5440 87.7950 67.9070 99.2218 99.5992 99.5562
+46 "E06" 0.797860 0.786020 0.637060 3.24176 4.79711 5.19033
+47 "E07" 57.9520 50.1120 24.1350 99.8375 83.3955 73.6909
+48 "E08" 55.6470 45.0930 20.4680 99.9381 76.3745 66.0755
+49 "E09" 1.80460 2.87160 1.55130 4.48621 18.0239 4.30997
+50 "E10" 18.2860 18.0540 14.0520 52.1381 63.9931 59.5867
+51 "F01" 0.821450 0.811590 0.652140 3.57770 5.15708 5.53341
+52 "F02" 37.5450 31.1590 14.8630 96.5601 68.3501 70.3025
+53 "F03" 9.33780 7.45630 25.3510 10.9434 23.1229 99.7024
+54 "F04" 12.1560 19.3000 4.12860 23.1756 99.6011 0.0467819
+55 "F05" 54.5560 53.7060 42.1400 94.0193 93.9462 95.0190
+56 "F06" 6.40720 6.33990 5.06690 17.0382 27.4615 23.1311
+57 "F07" 35.9410 31.6060 12.5440 92.1715 71.6310 56.7871
+58 "F08" 37.1160 32.6870 16.7870 90.7079 71.9484 62.7050
+59 "F09" 17.6330 26.2060 16.5150 36.1091 99.9776 44.7211
+60 "F10" 0.817450 0.803300 0.648070 3.03016 4.52847 4.93133
+61 "G01" 88.1180 87.3790 67.6390 99.6063 99.6546 99.6378
+62 "G02" 14.1420 14.4220 21.7790 31.5235 64.4645 88.2405
+63 "G03" 27.0730 16.1500 6.52890 99.3019 18.8709 29.9070
+64 "G04" 19.3760 9.31950 1.23360 92.7481 0.0514771 0.996714
+65 "G05" 33.4270 32.9730 25.9370 79.6111 83.8506 83.8771
+66 "G06" 11.0640 10.9460 8.65770 33.3576 46.6792 41.8190
+67 "G07" 16.1500 13.5220 3.95020 63.4164 39.5547 3.47786
+68 "G08" 37.6610 32.4480 16.8480 92.7905 70.2031 67.4679
+69 "G09" 21.4030 28.6380 6.93640 38.7589 99.9778 0.496405
+70 "G10" 88.7630 88.0110 68.0300 99.1885 99.2266 99.3112
+71 "H01" 18.2340 18.0030 14.0320 57.6571 67.9088 64.2915
+72 "H02" 7.93780 10.0280 2.21420 16.0406 60.3414 0.0759039
+73 "H03" 5.32950 3.13280 7.61040 18.4523 0.0274370 48.8589
+74 "H04" 58.2760 57.3920 3.84380 97.3325 94.4934 8.98711
+75 "H05" 18.0560 17.8320 13.9270 55.2642 65.9668 62.1343
+76 "H06" 27.8670 27.4770 21.6560 72.6082 79.1552 77.6922
+77 "H07" 40.9840 36.1270 18.8500 94.1035 76.7796 72.9008
+78 "H08" 38.1290 32.7720 16.0850 93.5800 70.8410 66.5429
+79 "H09" 10.9120 18.9050 3.25920 18.3400 97.6540 1.11200
+80 "H10" 18.3150 18.0830 14.0770 54.1252 65.7287 61.1352
+81 "I01" 0.877970 0.866490 0.692530 3.89803 5.52321 5.87104
+82 "I02" 20.9640 18.5090 28.0310 63.1732 61.5508 99.2533
+83 "I03" 33.5760 40.9120 5.28710 76.4298 99.9653 9.91792
+84 "I04" 28.7570 16.5770 19.4170 97.5162 15.7443 99.9554
+85 "I05" 8.34090 8.24580 6.46760 26.2127 37.6943 32.9267
+86 "I06" 47.5260 46.8020 36.7430 91.1191 92.1693 92.7183
+87 "I07" 18.5620 14.2840 2.53620 71.7667 36.8616 0.0762142
+88 "I08" 10.9170 8.92160 2.27380 49.8294 27.4643 0.0776073
+89 "I09" 17.4380 28.5650 5.55330 34.9025 99.9410 12.7946
+90 "I10" 0.821180 0.807980 0.647830 3.47476 5.04339 5.42659
+91 "J01" 88.4510 87.7100 67.8900 99.8550 99.9501 99.9252
+92 "J02" 28.2480 36.7910 28.9770 62.3789 99.9741 75.3109
+93 "J03" 46.4790 40.8160 3.05390 99.6210 80.8061 2.48062
+94 "J04" 10.7330 14.6700 25.4470 21.5610 81.2289 77.0705
+95 "J05" 1.94760 1.93530 1.62720 4.71988 8.24480 7.82566
+96 "J06" 72.4300 71.6040 56.5980 98.1204 98.3388 99.1073
+97 "J07" 39.0010 31.8440 12.6630 96.0770 67.9382 46.5024
+98 "J08" 41.2900 34.6190 13.3580 96.8660 72.4588 54.8591
+99 "J09" 34.2630 30.1940 5.39700 90.2234 70.2202 0.0623386
+100 "J10" 88.6890 87.9420 67.9450 99.2152 99.2801 99.5654
+101 "K01" 18.2870 18.0550 14.0940 59.0025 69.1409 65.5487
+102 "K02" 69.7990 64.7750 36.6120 99.6822 95.7093 91.7473
+103 "K03" 65.6850 71.9500 50.5420 96.8438 99.8905 97.2996
+104 "K04" 65.7350 62.3550 54.3800 98.3442 95.6648 99.6471
+105 "K05" 56.6400 60.8890 55.7810 93.0084 99.2612 98.7282
+106 "K06" 40.8830 40.3150 31.7710 87.4846 90.0455 89.9846
+107 "K07" 14.7360 14.5610 11.2750 47.0421 59.2067 53.9164
+108 "K08" 2.93200 2.88900 2.29030 7.41163 11.4541 9.79805
+109 "K09" 26.2580 30.2340 4.53580 63.1341 93.2221 0.0298406
+110 "K10" 18.2730 18.0420 14.0570 55.2930 66.4439 62.3838
+111 "L01" 0.862840 0.850990 0.693220 3.87962 5.48970 5.85651
+112 "L02" 6.16360 3.50110 1.81220 38.1729 0.0962079 3.80448
+113 "L03" 26.3380 13.4420 1.40110 99.7165 4.53211 1.36954
+114 "L04" 38.5470 28.0920 19.9310 99.9731 55.0042 83.5153
+115 "L05" 39.7740 29.2290 14.6560 99.9422 58.7798 61.5525
+116 "L06" 46.5510 31.0860 1.68400 99.8180 54.7591 3.14563
+117 "L07" 40.3200 44.8880 2.28100 81.9478 98.4938 0.688775
+118 "L08" 30.8790 30.5350 4.30920 83.9547 79.4768 0.0391914
+119 "L09" 34.3480 43.5170 4.20490 69.3966 99.9270 0.0658071
+120 "L10" 0.800670 0.788840 0.635170 3.97289 5.83698 5.98220
+121 "M01" 18.1930 17.9660 14.0100 59.6309 69.7719 66.1588
+122 "M02" 23.9480 12.4740 6.90150 99.7706 4.70147 59.4602
+123 "M03" 4.91740 2.88340 3.24780 28.1391 0.561666 23.5497
+124 "M04" 22.8350 11.3090 2.24090 99.8063 1.68667 20.7720
+125 "M05" 37.8580 20.9420 3.22960 99.8275 25.8631 6.21660
+126 "M06" 68.6210 59.7530 4.77180 97.8760 92.5321 9.30162
+127 "M07" 62.1430 60.5650 3.45590 96.8719 96.3609 10.1197
+128 "M08" 36.4040 42.0820 3.08240 80.3325 98.4745 0.724150
+129 "M09" 3.84880 2.97780 0.821780 16.4467 9.88207 4.80164
+130 "M10" 18.2420 18.0100 14.0270 56.4231 67.0989 63.5167
+131 "N01" 88.2290 87.5100 67.7730 99.7306 99.7388 99.7304
+132 "N02" 18.2350 18.0070 14.0330 58.4655 68.6862 65.0329
+133 "N03" 0.902820 0.890040 0.724140 3.68406 5.33264 5.63854
+134 "N04" 88.5680 87.8170 67.9670 99.6812 99.9152 99.8513
+135 "N05" 18.1220 17.8970 13.9580 56.8631 66.9076 63.7330
+136 "N06" 0.910530 0.896090 0.727430 3.61138 5.17412 5.50048
+137 "N07" 88.7080 87.9570 67.9660 99.5758 99.5768 99.5772
+138 "N08" 18.1980 17.9690 14.0030 56.1060 66.6952 63.0654
+139 "N09" 0.843350 0.831020 0.672600 3.93895 5.79967 5.81986
+140 "N10" 88.8180 88.0710 68.1240 99.5289 99.6025 99.5746
END_DATA
diff --git a/ref/afiles b/ref/afiles
index bd8a2f1..1b1fc6c 100644
--- a/ref/afiles
+++ b/ref/afiles
@@ -17,6 +17,7 @@ CMP_DT_003.cht
CMP_Digital_Target-4.cht
CMP_Digital_Target-4.ti2
CMP_Digital_Target-4.cie
+CMP_Digital_Target-7.cht
ColorChecker.cht
ColorChecker.cie
ColorChecker.ti2
diff --git a/ref/linear.cal b/ref/linear.cal
index 9c88605..bdbf22c 100644
--- a/ref/linear.cal
+++ b/ref/linear.cal
@@ -2,7 +2,7 @@ CAL
DESCRIPTOR "Argyll Device Calibration Curves"
ORIGINATOR "Argyll synthcal"
-CREATED "Mon Oct 26 01:10:48 2015"
+CREATED "Tue Sep 27 01:29:33 2016"
DEVICE_CLASS "DISPLAY"
COLOR_REP "RGB"
diff --git a/ref/sRGB.icm b/ref/sRGB.icm
index 9d33a4b..59b4507 100644
--- a/ref/sRGB.icm
+++ b/ref/sRGB.icm
Binary files differ
diff --git a/ref/strange.cal b/ref/strange.cal
index 5f2e94d..94bacf5 100644
--- a/ref/strange.cal
+++ b/ref/strange.cal
@@ -2,7 +2,7 @@ CAL
DESCRIPTOR "Argyll Device Calibration Curves"
ORIGINATOR "Argyll synthcal"
-CREATED "Mon Oct 26 01:10:48 2015"
+CREATED "Tue Sep 27 01:29:33 2016"
DEVICE_CLASS "DISPLAY"
COLOR_REP "RGB"
diff --git a/rspl/Jamfile b/rspl/Jamfile
index 37c2c37..0d93acc 100644
--- a/rspl/Jamfile
+++ b/rspl/Jamfile
@@ -3,8 +3,8 @@
# Optimization and Debug flags
-PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
-#PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
#PREF_CCFLAGS += $(CCPROFFLAG) ; # Profile flags
#PREF_LINKFLAGS += $(LINKPROFFLAG) ; # Profile flags
#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
@@ -59,9 +59,14 @@ if $(BUILD_TESTS) {
# Test code
-if $(HOME) = "d:\\usr\\graeme" && $(PWD) = "/src/argyll/rspl" {
+if ( $(HOME) = "D:\\usr\\graeme" && $(PWD) = "/src/argyll/rspl" )
+ || ( $(HOME) = "/Users/graeme" && $(PWD) = "/Users/graeme/src/argyll/rspl" ) {
# Main tt : tt.c : : ../xicc : : : ../plot/libvrml ../icc/libicc ;
+ Main lchw : lchw.c : : : ../h ../numlib ../icc ../plot : : ../plot/libplot ../icc/libicc ../numlib/libui ../numlib/libnum ;
+ Main lchw_solve : lchw_solve.c : : : ../h ../numlib ../icc ../plot : : ../plot/libplot ../icc/libicc ../numlib/libui ../numlib/libnum ;
+ Main lchw_deriv : lchw_deriv.c : : : ../h ../numlib ../icc ../plot : : ../plot/libplot ../icc/libicc ../numlib/libui ../numlib/libnum ;
+ Main lchw_2deriv : lchw_2deriv.c : : : ../h ../numlib ../icc ../plot : : ../plot/libplot ../icc/libicc ../numlib/libui ../numlib/libnum ;
Main crossv : crossv.c : : : ../numlib ../plot : : ../plot/libplot ../numlib/libui ../numlib/libnum ;
}
diff --git a/rspl/rev.c b/rspl/rev.c
index 1dbf6cc..f2f717b 100644
--- a/rspl/rev.c
+++ b/rspl/rev.c
@@ -1,4 +1,7 @@
+/* First cut at lchw weighted. Problems with list size, memory use and */
+/* performance. Version uses direct bwd cell nnrev[] creation */
+
/*
* Argyll Color Correction System
* Multi-dimensional regularized spline data structure
@@ -19,27 +22,13 @@
/* TTBD:
- Should fix the clipping case so that a direction weighting
- funtion can be applied. This should be used just like
- the perceptual case to increase L* constance for dark
- colors. This would entail large scale changes though,
- since a lot of code assumes minimal euclidean distance
- goal, from the cell selection structure [ See fill_nncell(),
- fill_nncell() and users of calc_fwd_nn_cell_list() ] and
- the within cell computation [ ie. See nnearest_clip_solve(),
- clipn_setsort() etc. ]
- XYZ PCS couldn't work with a simple weighting - it would have
- to be a position dependent weighting.
- The SVD least squares computation case makes this hard to change ?
- Would have to feed in a weighting function, or can it be general ?
- -
- Can this be solved some other way, ie. by using gamut
- mapping type look up ? Problem is precision.
- -
- Vector clip could be used (if intent can be turned
- into computable vector clip direction), but it is slow,
- because it search all cells from source until it
- hits surface.
+ Add option/function to return a gamut surface triangle list
+ based on the rev setup thinned vertex list.
+ Need to add code to convert over ink edges to triangles
+ and then shadow test them though.
+
+ XYZ PCS doesn't work with a LCh weighting, although this is
+ no an issue when xicc uses separate Jab rspl for clip case (CAM CLIP).
Allow function callback to set auxiliary values for
flag RSPL_AUXLOCUS.
@@ -59,7 +48,7 @@
Basic function requirements: exact, auxil, locus, clip
- Fwd cell - reverse cell list lookup
+ Fwd cell - fxcell list lookup
Basic layout di -> fdi + auxils + ink limit
@@ -119,8 +108,13 @@
//#include "dmalloc.h"
//#undef DMALLOC_GLOBALS
-#undef DEBUG1 /* Higher level code */
-#undef DEBUG2 /* Lower level code */
+#define DOSORT /* [def] Cell sort for better speed */
+
+#undef REVTABLESTATS /* [und] Reverse table stats */
+#undef REVVRML /* [und] Reverse table plots */
+
+#undef DEBUG1 /* [und] Higher level code */
+#undef DEBUG2 /* [und] Lower level code */
/* Debug memory usage accounting */
#ifdef NEVER
@@ -151,8 +145,6 @@ int thissz, lastsz = -1;
/* Set STATS in rev.h */
-#define DOSORT /* Cell sort */
-
/* Print a vectors value */
#define DBGVI(text, dim, out, vec, end) \
{ int pveci; \
@@ -175,6 +167,23 @@ int thissz, lastsz = -1;
printf(end); \
}
+#if defined(DEBUG1) || defined(DEBUG2)
+# define REVTABLESTATS /* [und] Reverse table stats */
+#endif
+
+#ifdef REVTABLESTATS
+#pragma message("!!!!!!!!! REVTABLESTATS set in rspl/rev.c !!!!!!!!!!!")
+#endif
+
+#ifdef REVVRML
+#pragma message("!!!!!!!!! REVVRML set in rspl/rev.c !!!!!!!!!!!")
+#include "vrml.h"
+#endif
+
+#ifdef CHECK_NNLU
+#pragma message("!!!!!!!!! CHECK_NNLU set in rspl/rspl.h !!!!!!!!!!!")
+#endif
+
/* Do an arbitrary printf */
#define DBGI(text) printf text ;
@@ -209,7 +218,7 @@ int thissz, lastsz = -1;
#endif
/* Debug string routines */
-static char *pcellorange(cell *c);
+static char *pcellorange(fxcell *c);
/* Convention is to use:
i to index grid points u.a
@@ -225,9 +234,9 @@ static char *pcellorange(cell *c);
static void make_rev(rspl *s);
static void init_revaccell(rspl *s);
-static cell *get_rcell(schbase *b, int ix, int force);
-static void uncache_rcell(revcache *r, cell *cp);
-#define unget_rcell(r, cp) uncache_rcell(r, cp) /* These are the same */
+static fxcell *get_fxcell(schbase *b, int ix, int force);
+static void uncache_fxcell(revcache *r, fxcell *cp);
+#define unget_fxcell(r, cp) uncache_fxcell(r, cp) /* These are the same */
static void invalidate_revaccell(rspl *s);
static int decrease_revcache(revcache *rc);
@@ -285,7 +294,7 @@ static void rev_reduce_cache(size_t size) {
ram += rsi->sz;
if (size > ram)
- error("rev_reduce_cache: run out of rev virtual memory!");
+ error("rev_reduce_cache: run out of rev virtual memory! (want %d, got %d)",size,ram);
//printf("~1 size = %d, g_test_ram = %d\n",size,g_test_ram);
//printf("~1 rev: Reducing cache because alloc of %d bytes failed. Reduced from %d to %d MB\n",
@@ -304,12 +313,13 @@ static void rev_reduce_cache(size_t size) {
}
//printf("~1 rev instance ram = %d MB\n",rsi->sz/1000000);
}
-//fprintf(stdout, "%c~~1 There %s %d rev cache instance%s with %d Mbytes limit\n",
-// cr_char,
-// g_no_rev_cache_instances > 1 ? "are" : "is",
-// g_no_rev_cache_instances,
-// g_no_rev_cache_instances > 1 ? "s" : "",
-// ram/1000000);
+ if (g_rev_instances != NULL && g_rev_instances->sb->s->verbose)
+ printf("%cThere %s %d rev cache instance%s with %lu Mbytes limit\n",
+ cr_char,
+ g_no_rev_cache_instances > 1 ? "are" : "is",
+ g_no_rev_cache_instances,
+ g_no_rev_cache_instances > 1 ? "s" : "",
+ (unsigned long)ram/1000000);
}
/* Check that the requested allocation plus 20 M Bytes */
@@ -403,7 +413,8 @@ rev_set_limit_rspl(
) {
schbase *b;
- DBG(("rev: setting ink limit function 0x%x and limit %f\n",limit,limitv));
+ DBG(("rev: setting ink limit function %p and limit %f\n",limit,limitv));
+
/* This is a restricted size function */
if (s->di > MXRI)
error("rspl: rev_set_limit can't handle di = %d",s->di);
@@ -447,22 +458,58 @@ rev_get_limit_rspl(
}
}
+/* Set the RSPL_NEARCLIP LCh weightings. */
+/* Will only work with L*a*b* like output spaces. */
+/* Calling this will clear the reverse interpolaton cache. */
+static void rev_set_lchw(
+ struct _rspl *s, /* this */
+ double lchw[MXRO] /* Weighting */
+) {
+ int f;
+
+ DBG(("rev: setting LCH weightings %f %f %f \n",lchw[0], lchw[1], lchw[2]));
+
+ /* This is a restricted size function */
+ if (s->di > MXRI)
+ error("rspl: rev_set_lchw can't handle di = %d",s->di);
+ if (s->fdi > MXRO || s->fdi != 3)
+ error("rspl: rev_set_lchw can't handle fdi = %d",s->fdi);
+
+ s->rev.lchweighted = 1;
+ for (f = 0; f < s->fdi; f++) {
+ s->rev.lchw[f] = lchw[f];
+ s->rev.lchw_sq[f] = s->rev.lchw[f] * s->rev.lchw[f];
+ }
+ s->rev.lchw_chsq = s->rev.lchw_sq[1] - s->rev.lchw_sq[2]; /* C - H squared weight */
+
+ if (s->rev.inited) { /* If cache and acceleration has been allocated */
+ invalidate_revaccell(s); /* Invalidate the reverse cache */
+ }
+}
+
#define RSPL_CERTAIN 0x80000000 /* WILLCLIP hint is certain */
#define RSPL_WILLCLIP2 (RSPL_CERTAIN | RSPL_WILLCLIP) /* Clipping will certainly be needed */
+#ifdef CHECK_NNLU
+static void check_nn(rspl *s, double *oval, co *cpp);
+static void print_nnck(rspl *s);
+#endif
+
/* Do reverse interpolation given target output values and (optional) auxiliary target */
/* input values. Return number of results and clipping flag. If return value == mxsoln, */
/* then there might be more results. The target values returned will correspond to the */
/* actual (posssibly clipped) point. The return value is the number of solutions + */
/* a clipped flag. Properly set hint flags improve performance, but a correct result should */
/* be returned if the RSPL_NEARCLIP is set, even if they are not set correctly. */
+/* If RSPL_NONNSETUP is set, then rev.fastsetup will be set for this call, avoiding */
+/* initialization of the nngrid if RSPL_NEARCLIP hasn't been used before. */
static int
rev_interp_rspl(
rspl *s, /* this */
int flags, /* Hint flag */
int mxsoln, /* Maximum number of solutions allowed for */
int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no auxiliaries) */
- double cdir[MXRO], /* Clip vector direction wrt to cpp[0].v and length - NULL if not used */
+ double cdir[MXRO], /* Clip vector direction and length - NULL if not used */
co *cpp /* Given target output space value in cpp[0].v[] + */
/* target input space auxiliaries in cpp[0].p[], return */
/* input space solutions in cpp[0..retval-1].p[], and */
@@ -473,6 +520,7 @@ rev_interp_rspl(
schbase *b = NULL; /* Base search information */
double auxv[MXRI]; /* Locus proportional auxiliary values */
int didclip = 0; /* flag - set if we clipped the target */
+ int fastsetup; /* fastsetup on entry */
DBGV(("\nrev interp called with out targets", fdi, " %f", cpp[0].v, "\n"));
@@ -496,7 +544,11 @@ rev_interp_rspl(
DBG(("di = %d, fdi = %d\n",di, fdi));
DBG(("flags = 0x%x\n",flags));
- mxsoln &= RSPL_NOSOLNS; /* Prevent silliness */
+ fastsetup = s->rev.fastsetup; /* fastsetup on entry */
+ if (flags & RSPL_NONNSETUP) /* Avoid triggering nnsetup on this call */
+ s->rev.fastsetup = 1;
+
+ mxsoln &= RSPL_NOSOLNS; /* Prevent silliness */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Auxiliary is proportion of locus, so we need to find locus extent */
@@ -550,7 +602,7 @@ rev_interp_rspl(
b = init_search(s, flags, cpp[0].p, auxm, cpp[0].v, cdir, cpp, mxsoln, exact);
else
adjust_search(s, flags, auxv, exact); /* Using proportion of locus aux */
-
+
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* If hinted that we will not need to clip, look for exact solution. */
if (!(flags & RSPL_WILLCLIP)) {
@@ -570,7 +622,7 @@ rev_interp_rspl(
/* Setup, sort and search the list */
search_list(b, rip, s->get_next_touch(s));
} else {
- DBG(("Got NULL list (point outside range) for first exact reverse cell\n"));
+ DBG(("Got NULL list (point outside range) for first exact fxcell\n"));
}
/* If we selected exact aux, but failed to find a solution, relax expectation */
@@ -587,7 +639,7 @@ rev_interp_rspl(
/* Setup, sort and search the list */
search_list(b, rip, s->get_next_touch(s));
} else {
- DBG(("Got NULL list (point outside range) for nearest search reverse cell\n"));
+ DBG(("Got NULL list (point outside range) for nearest search fxcell\n"));
}
}
}
@@ -595,6 +647,13 @@ rev_interp_rspl(
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* If the exact search failed, and we should look for a nearest solution */
if (b->nsoln == 0 && (flags & RSPL_NEARCLIP)) {
+#ifdef CHECK_NNLU
+ int f, fdi = s->fdi;
+ double oval[MXRO]; /* Save the input target value for check_nn() */
+
+ for (f = 0; f < fdi; f++)
+ oval[f] = cpp[0].v[f];
+#endif
DBG(("Trying nearest search\n"));
#ifdef STATS
@@ -603,10 +662,6 @@ rev_interp_rspl(
/* We get returned a list of cube base indexes of all cubes that have */
/* the closest valid vertex value to the target value. */
- /* (This may not result in the true closest point if the geometry of */
- /* the vertex values is localy non-smooth or self intersecting, */
- /* but seems to return a good result in most realistic situations ?) */
-
adjust_search(s, flags, NULL, clipn);
/* Get list of cells enclosing nearest vertex */
@@ -616,8 +671,12 @@ rev_interp_rspl(
DBG(("Got NULL list! (point inside gamut \?\?) for nearest search\n"));
}
- if (b->nsoln > 0)
+ if (b->nsoln > 0) {
didclip = RSPL_DIDCLIP;
+#ifdef CHECK_NNLU
+ check_nn(s, oval, cpp); /* Run diagnostic to check sanity of result */
+#endif
+ }
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -625,7 +684,7 @@ rev_interp_rspl(
if (b->nsoln == 0 && b->canvecclip) {
/* Find clipping solution in vector direction */
line ln; /* Structure to hold line context */
- unsigned int tcount; /* grid touch count for this opperation */
+ unsigned int tcount; /* grid touch count for this operation */
DBG(("Starting a clipping vector search now!!\n"));
@@ -641,7 +700,7 @@ rev_interp_rspl(
//~~1 HACK!!! should be <= 1.0 !!!
for (; ln.t <= 2.0; rip = next_line_cell(&ln)) {
if (rip == NULL) {
- DBG(("Got NULL list for this reverse cell\n"));
+ DBG(("Got NULL list for this fxcell\n"));
continue;
}
@@ -685,7 +744,7 @@ rev_interp_rspl(
/* Setup, sort and search the list */
search_list(b, rip, s->get_next_touch(s));
} else {
- DBG(("Got NULL list (point outside range) for first exact reverse cell\n"));
+ DBG(("Got NULL list (point outside range) for first exact fxcell\n"));
}
/* If we selected exact aux, but failed to find a solution, relax expectation */
@@ -702,7 +761,7 @@ rev_interp_rspl(
/* Setup, sort and search the list */
search_list(b, rip, s->get_next_touch(s));
} else {
- DBG(("Got NULL list (point outside range) for nearest search reverse cell\n"));
+ DBG(("Got NULL list (point outside range) for nearest search fxcell\n"));
}
}
@@ -729,6 +788,8 @@ rev_interp_rspl(
}
DBG(("rev interp returning %d solutions%s\n",b->nsoln, didclip ? " [clip]" : ""));
+ s->rev.fastsetup = fastsetup; /* retore fastsetup state */
+
return b->nsoln | didclip;
}
@@ -958,23 +1019,23 @@ rev_locus_rspl(
/* ------------------------------------------------ */
/* subroutines of top level reverse lookup routine */
-static int exact_setsort(schbase *b, cell *c);
+static int exact_setsort(schbase *b, fxcell *c);
static int exact_compute(schbase *b, simplex *x);
-static int auxil_setsort(schbase *b, cell *c);
-static int auxil_check(schbase *b, cell *c);
+static int auxil_setsort(schbase *b, fxcell *c);
+static int auxil_check(schbase *b, fxcell *c);
static int auxil_compute(schbase *b, simplex *x);
-static int locus_setsort(schbase *b, cell *c);
-static int locus_check(schbase *b, cell *c);
+static int locus_setsort(schbase *b, fxcell *c);
+static int locus_check(schbase *b, fxcell *c);
static int locus_compute(schbase *b, simplex *x);
-static int clipv_setsort(schbase *b, cell *c);
-static int clipv_check(schbase *b, cell *c);
+static int clipv_setsort(schbase *b, fxcell *c);
+static int clipv_check(schbase *b, fxcell *c);
static int clipv_compute(schbase *b, simplex *x);
-static int clipn_setsort(schbase *b, cell *c);
-static int clipn_check(schbase *b, cell *c);
+static int clipn_setsort(schbase *b, fxcell *c);
+static int clipn_check(schbase *b, fxcell *c);
static int clipn_compute(schbase *b, simplex *x);
/* Allocate the search base structure */
@@ -985,8 +1046,8 @@ alloc_sb(rspl *s) {
error("rspl malloc failed - rev.sb structure");
INCSZ(s, sizeof(schbase));
- b->s = s; /* rsp */
- b->pauxcell = /* Previous solution cell indexes */
+ b->s = s; /* rsp */
+ b->pauxcell = /* Previous solution cell indexes */
b->plmaxcell =
b->plmincell = -1;
@@ -1010,7 +1071,7 @@ init_search(
int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no auxiliaries) */
/* Locus search will search for max/min of first valid auxlilary */
double *v, /* Output value target, NULL if none */
- double *cdir, /* Clip vector direction, NULL if none */
+ double *cdir, /* Clip vector direction/LCh weighting, NULL if none */
co *cpp, /* Array that hold solutions, NULL if none. */
int mxsoln, /* Maximum number of solutions allowed for */
enum ops op /* Type of reverse search operation requested */
@@ -1019,15 +1080,14 @@ init_search(
int e, di = s->di;
int f, fdi = s->fdi;
- DBG(("Initializing search\n"));
+ DBG(("Initializing search di %d fdi %d\n",s->di,s->fdi));
if (s->rev.inited == 0) /* Compute reverse info if it doesn't exist */
make_rev(s);
/* If first time initialisation (Fourth section init) */
- if ((b = s->rev.sb) == NULL) {
+ if ((b = s->rev.sb) == NULL)
b = alloc_sb(s);
- }
/* Init some basic search info */
b->op = op; /* operation */
@@ -1065,7 +1125,7 @@ init_search(
/* Figure out if the clip direction is meaningfull */
/* Check that the clip vector makes sense */
- if (cdir != NULL) { /* Clip vector is specified */
+ if (!(flags & RSPL_NEARCLIP) && cdir != NULL) { /* Clip vector is specified */
double ss;
for (ss = 0.0, f = 0; f < fdi; f++) {
double tt = cdir[f];
@@ -1272,9 +1332,9 @@ set_search_limit(
b = alloc_sb(s);
}
- s->limitf = limitf; /* Input limit function */
- s->lcntx = lcntx; /* Context passed to limit() */
- s->limitv= INKSCALE * limitv; /* Context passed to values not to be exceedded by limit() */
+ s->limitf = limitf; /* Input limit function */
+ s->lcntx = lcntx; /* Context passed to limit() */
+ s->limitv = INKSCALE * limitv; /* Context passed to values not to be exceeded by limit() */
if (limitf != NULL) {
s->limiten = 1; /* enable limiting by default */
} else
@@ -1309,7 +1369,7 @@ schbase *b /* Base search information */
/* Sorted cell list */
if (b->lclistz > 0) {
free(b->lclist);
- DECSZ(b->s, b->lclistz * sizeof(cell *));
+ DECSZ(b->s, b->lclistz * sizeof(fxcell *));
b->lclist = NULL;
b->lclistz = 0;
}
@@ -1350,12 +1410,14 @@ calc_fwd_cell_list(
}
rpp += mi * s->rev.coi[f]; /* Accumulate reverse grid pointer */
}
+ s->rev.sb->rix = rpp - s->rev.rev; /* Set diagnostic value */
+
if (*rpp == NULL)
return NULL;
return (*rpp) + 3;
}
-void alloc_simplexes(cell *c, int nsdi);
+void alloc_simplexes(fxcell *c, int nsdi);
/* Given a pointer to a list of fwd cells, cull cells that */
/* cannot contain or improve the solution, sort the list, */
@@ -1369,7 +1431,7 @@ unsigned int tcount /* grid touch count for this operation */
rspl *s = b->s;
int nsdi;
int i;
- int nilist; /* Number in cell list */
+ int nilist; /* Number in cell list */
unsigned int stouch; /* Simplex touch count */
DBG(("search_list called\n"));
@@ -1381,31 +1443,31 @@ unsigned int tcount /* grid touch count for this operation */
if (b->lclistz > 0) { /* Free old space before allocating new */
free(b->lclist);
- DECSZ(b->s, b->lclistz * sizeof(cell *));
+ DECSZ(b->s, b->lclistz * sizeof(fxcell *));
}
b->lclistz = 0;
/* Allocate enough space for all the candidate cells */
- if ((b->lclist = (cell **)rev_malloc(s, rip[-3] * sizeof(cell *))) == NULL)
+ if ((b->lclist = (fxcell **)rev_malloc(s, rip[-3] * sizeof(fxcell *))) == NULL)
error("rev: malloc failed - candidate cell list, count %d",rip[-3]);
b->lclistz = rip[-3]; /* Current allocated space */
- INCSZ(b->s, b->lclistz * sizeof(cell *));
+ INCSZ(b->s, b->lclistz * sizeof(fxcell *));
}
/* Get the next simplex touch count, so that we don't search shared */
/* face simplexes more than once in this pass through the cells. */
if ((stouch = ++s->rev.stouch) == 0) { /* If touch count rolls over */
- cell *cp;
+ fxcell *cp;
stouch = s->rev.stouch = 1;
- DBG(("touch has rolled over, resetting it\n"));
/* For all of the cells */
+ DBG(("touch has rolled over, resetting it\n"));
for (cp = s->rev.cache->mrubot; cp != NULL; cp = cp->mruup) {
int nsdi;
if (cp->s == NULL) /* Cell has never been used */
continue;
- /* For all the simplexes in the cell */
+ /* For all the simplexes in the fxcell */
for (nsdi = 0; nsdi <= s->di; nsdi++) {
if (cp->sx[nsdi] != NULL) {
int si;
@@ -1419,20 +1481,20 @@ unsigned int tcount /* grid touch count for this operation */
}
/* For each chunk of the list that we can fit in the rcache: */
- for(; *rip != -1;) {
+ for (; *rip != -1;) {
/* Go through all the candidate fwd cells, and build up the list of search cells */
- for(nilist = 0; *rip != -1; rip++) {
+ for (nilist = 0; *rip != -1; rip++) {
int ix = *rip; /* Fwd cell index */
float *fcb = s->g.a + ix * s->g.pss; /* Pointer to base float of fwd cell */
- cell *c;
+ fxcell *c;
if (TOUCHF(fcb) >= tcount) { /* If we have visited this cell before */
DBG((" Already touched cell index %d\n",ix));
continue;
}
/* Get pointers to cells from cache, and lock it in the cache */
- if ((c = get_rcell(b, ix, nilist == 0 ? 1 : 0)) == NULL) {
+ if ((c = get_fxcell(b, ix, nilist == 0 ? 1 : 0)) == NULL) {
static int warned = 0;
if (!warned) {
warning("%cWarning - Reverse Cell Cache exausted, processing in chunks",cr_char);
@@ -1442,7 +1504,7 @@ unsigned int tcount /* grid touch count for this operation */
if (nilist == 0) {
/* This should never happen, because nz force should prevent it */
revcache *rc = s->rev.cache;
- cell *cp;
+ fxcell *cp;
int nunlk = 0;
/* Double check that there are no unlocked cells */
for (cp = rc->mrubot; cp != NULL && cp->refcount > 0; cp = cp->mruup) {
@@ -1463,7 +1525,7 @@ unsigned int tcount /* grid touch count for this operation */
/* Check mandatory conditions, and compute search key */
if (!b->setsort(b, c)) {
DBG(("cell %d rejected from list\n",ix));
- unget_rcell(s->rev.cache, c);
+ unget_fxcell(s->rev.cache, c);
continue;
}
DBG(("cell %d accepted into list\n",ix));
@@ -1483,7 +1545,7 @@ unsigned int tcount /* grid touch count for this operation */
{ /* Special case, adjust sort values */
double min = INF_DIST, max = -INF_DIST;
for (i = 0; i < nilist; i++) {
- cell *c = b->lclist[i];
+ fxcell *c = b->lclist[i];
if (c->sort < min)
min = c->sort;
if (c->sort > max)
@@ -1492,7 +1554,7 @@ unsigned int tcount /* grid touch count for this operation */
max = min + max; /* Total of min/max */
min = 0.5 * max; /* Average sort value */
for (i = 0; i < nilist; i++) {
- cell *c = b->lclist[i];
+ fxcell *c = b->lclist[i];
if (c->ix == b->plmincell || c->ix == b->plmaxcell) {
c->sort = -1.0; /* Put previous solution cells at head of list */
} else if (c->sort > min) {
@@ -1505,7 +1567,7 @@ unsigned int tcount /* grid touch count for this operation */
case clipv:
case clipn:
#define HEAP_COMPARE(A,B) (A->sort < B->sort)
- HEAPSORT(cell *,b->lclist, nilist)
+ HEAPSORT(fxcell *,b->lclist, nilist)
#undef HEAP_COMPARE
break;
default:
@@ -1531,7 +1593,7 @@ unsigned int tcount /* grid touch count for this operation */
/* For each cell in the list */
for (i = 0; i < nilist; i++) {
- cell *c = b->lclist[i];
+ fxcell *c = b->lclist[i];
#ifdef STATS
s->rev.st[b->op].csearched++;
@@ -1593,8 +1655,8 @@ unsigned int tcount /* grid touch count for this operation */
nsdi++; /* Continue through increasing sub-simplex dimenionality */
} /* until we get to the top. */
}
- /* Unlock the cache cell now that we're done with it */
- unget_rcell(s->rev.cache, b->lclist[i]);
+ /* Unlock the fxcell now that we're done with it */
+ unget_fxcell(s->rev.cache, b->lclist[i]);
} /* Next cell */
} /* Next chunk */
@@ -1651,16 +1713,16 @@ init_line(
}
DBGV(("current line cell = ", fdi, " %d", l->ci, "")); DBG((", t = %f, nvalid = %d\n",l->t,nvalid));
#ifdef DEBUG
-{
-int ii;
-double tt;
-printf("Current cell = ");
-for (ii = 0; ii < fdi; ii++) {
- tt = l->ci[ii] * s->rev.gw[ii] + s->rev.gl[ii];
- printf(" %f - %f",tt,tt+s->rev.gw[ii]);
-}
-printf("\n");
-}
+ {
+ int ii;
+ double tt;
+ printf("Current cell = ");
+ for (ii = 0; ii < fdi; ii++) {
+ tt = l->ci[ii] * s->rev.gw[ii] + s->rev.gl[ii];
+ printf(" %f - %f",tt,tt+s->rev.gw[ii]);
+ }
+ printf("\n");
+ }
#endif /* DEBUG */
if (nvalid)
return NULL;
@@ -1701,19 +1763,19 @@ next_line_cell(
DBGV(("current line cell =", fdi, " %d", l->ci, "")); DBG((", t = %f\n",l->t));
#ifdef DEBUG
-{
-int ii;
-double tt;
-printf("Current cell = ");
-for (ii = 0; ii < fdi; ii++) {
- tt = l->ci[ii] * s->rev.gw[ii] + s->rev.gl[ii];
- printf(" %f - %f",tt,tt+s->rev.gw[ii]);
-}
-printf("\n");
-}
+ {
+ int ii;
+ double tt;
+ printf("Current cell = ");
+ for (ii = 0; ii < fdi; ii++) {
+ tt = l->ci[ii] * s->rev.gw[ii] + s->rev.gl[ii];
+ printf(" %f - %f",tt,tt+s->rev.gw[ii]);
+ }
+ printf("\n");
+ }
#endif /* DEBUG */
- /* Compute reverse cell index */
+ /* Compute fxcell index */
for (rpp = s->rev.rev, f = 0; f < fdi; f++) {
if (l->ci[f] < 0 || l->ci[f] > rgres_1) { /* If outside valid reverse range */
DBG(("Outside list on dim %d, 0 <= %d <= %d\n", f, l->ci[f],rgres_1));
@@ -1729,164 +1791,599 @@ printf("\n");
/* ------------------------------------- */
/* Clip nearest support. */
-/* Track candidate cells nearest and furthest */
-struct _nncell_nf{
- double n, f;
-}; typedef struct _nncell_nf nncell_nf;
+/* Weighted distance function macro: */
+
+#define LCHW_SQ(fname, arg2type) \
+ \
+static double fname(rspl *s, double in1[MXDO], arg2type in2[MXDO]) { \
+ int f, fdi = s->fdi; \
+ double tt, rr = 0.0; \
+ \
+ /* Fall back */ \
+ if (!s->rev.lchweighted || fdi < 3) { \
+ for (f = 0; f < fdi; f++) { \
+ tt = in1[f] - (double)in2[f]; \
+ rr += tt * tt; \
+ } \
+ return rr; \
+ } \
+ \
+ { \
+ double dxsq = 0.0, dchsq; \
+ double dlsq, dcsq, dhsq; \
+ double dc, c1, c2; \
+ \
+ /* Compute delta L squared and delta E squared */ \
+ { \
+ double dl, da, db; \
+ dl = in1[0] - (double)in2[0]; \
+ da = in1[1] - (double)in2[1]; \
+ db = in1[2] - (double)in2[2]; \
+ \
+ dlsq = dl * dl; /* dl squared */ \
+ dchsq = da * da + db * db; \
+ } \
+ \
+ /* Add any extra dims */ \
+ for (f = 3; f < fdi; f++) { \
+ tt = in1[f] - (double)in2[f]; \
+ dxsq += tt * tt; \
+ } \
+ \
+ /* compute delta chromanance squared */ \
+ { \
+ /* Compute chromanance for the two colors */ \
+ c1 = sqrt(in1[1] * in1[1] + in1[2] * in1[2]); \
+ c2 = sqrt((double)in2[1] * (double)in2[1] + (double)in2[2] * (double)in2[2]); \
+ \
+ dc = c1 - c2; \
+ dcsq = dc * dc; \
+ } \
+ \
+ /* Compute delta hue squared */ \
+ /* (Hue is simply the orthogonal delta to chromanance in the a*b* plane) */ \
+ if ((dhsq = dchsq - dcsq) < 0.0) \
+ dhsq = 0.0; \
+ \
+ /* Compute weighted error squared */ \
+ rr = dxsq + s->rev.lchw_sq[0] * dlsq + s->rev.lchw_sq[1] * dcsq + s->rev.lchw_sq[2] * dhsq; \
+ \
+ return rr; \
+ } \
+}
-/* Given and empty nnrev index, create a list of */
-/* the forward cells that may contain the nearest value by */
-/* using and exaustive search. This is used for faststart. */
-static void fill_nncell(
- rspl *s,
- int *co, /* Integer coords of cell to be filled */
- int ix /* Index of cell to be filled */
-) {
+/* Compute weighted LCh output distance squared. */
+/* Weighting is to L,C,h, delta's squared - double[], double[] version */
+LCHW_SQ(lchw_sq, double)
+
+/* Weighting is to L,C,h, delta's squared - double[], float[] version */
+LCHW_SQ(lchw_sq_f, float)
+
+/* Notes:
+
+ Estimation accuracy is hobbled by 100% at HWEIGHT 1.0
+ compare to pure euclidean estimate, due to the conservative
+ maxDlc maxDh of points in group, but this reduces at larger
+ HWEIGHT's. The handicap also decreases quickly with tighter
+ group size, since C variation is diminished.
+
+ The handicap limits filtering efficiency for large group to group,
+ so ideally group size shouldn't be larger than about 10 DE in diameter.
+
+ It's not clear if any better approach is possible.
+*/
+
+#define NN_GCMIN (1e-6)
+
+/* Create a nn group. */
+/* If G != NULL, use it as group center rather than computing from members. */
+static void nn_grpinit(rspl *s, nn_grp *p, double **pnts, int npnts, double *G) {
+ int f, ee, ff, fdi = s->fdi;
int i;
- int e, di = s->di;
- int f, fdi = s->fdi;
- double cc[MXDO]; /* Cell center */
- double rr = 0.0; /* Cell radius */
- int **rpp, *rp;
- int gno = s->g.no;
- float *gp; /* Pointer to fwd grid points */
- nncell_nf *nf; /* cloase and far distances corresponding to list */
- double clfu = 1e38; /* closest furthest distance in list */
+ double *min[MXRO], *max[MXRO]; /* Pointers to points with min/max values */
+ double rad, radsq = -1.0; /* Span/radius squared */
+ int spf;
+ double dxsq = 0.0, desq, dchsq, dlcsq;
+ double dlsq, dcsq, dhsq;
+ double dc, c1, c2;
+ double c, minc = 1e200, maxc = -1.0;
+
+ if (G != NULL) {
+ for (f = 0; f < fdi; f++)
+ p->bcent[f] = G[f];
+
+ if (fdi >= 3) {
+ /* Track minimum and maximum member C squared */
+ for (i = 0; i < npnts; i++) {
+ c = pnts[i][1] * pnts[i][1] + pnts[i][2] * pnts[i][2];
+ if (c < minc)
+ minc = c;
+ if (c > maxc)
+ maxc = c;
+ }
+ }
+
+ } else if (npnts <= 2) {
+
+ /* Compute center as simple average */
+ for (f = 0; f < fdi; f++)
+ p->bcent[f] = 0.0;
- rpp = s->rev.nnrev + ix;
- rp = *rpp;
+ for (i = 0; i < npnts; i++) {
+ for (f = 0; f < fdi; f++)
+ p->bcent[f] += pnts[i][f];
+
+ if (fdi >= 3) {
+ /* Track minimum and maximum member C squared */
+ c = pnts[i][1] * pnts[i][1] + pnts[i][2] * pnts[i][2];
+ if (c < minc)
+ minc = c;
+ if (c > maxc)
+ maxc = c;
+ }
+ }
+ for (f = 0; f < fdi; f++)
+ p->bcent[f] *= 1.0/(double)npnts;
+
+ } else {
+ /* We establish a center point in un-weighted space, because this is */
+ /* what's needed for in-gamut work, and is computationally faster */
+ /* and easier than attempting it using weighted space. */
+
+ /* Find verticies of cell that have min and max values in output space */
+ for (f = 0; f < fdi; f++)
+ min[f] = max[f] = NULL;
+
+ for (ee = 0; ee < npnts; ee++) {
+ double *vp = pnts[ee];
+ for (f = 0; f < fdi; f++) {
+ if (min[f] == NULL || min[f][f] > vp[f])
+ min[f] = vp;
+ if (max[f] == NULL || max[f][f] < vp[f])
+ max[f] = vp;
+ }
+ }
+
+ /* Find the pair of points with the largest span (diameter) in output space */
+ for (ff = 0; ff < fdi; ff++) {
+ double ss;
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt;
+ tt = max[ff][f] - min[ff][f];
+ ss += tt * tt;
+ }
+ if (ss > radsq) {
+ radsq = ss;
+ spf = ff; /* Output dimension max was in */
+ }
+ }
+
+ /* Set initial bounding sphere */
+ for (f = 0; f < fdi; f++)
+ p->bcent[f] = (max[spf][f] + min[spf][f])/2.0;
+ radsq /= 4.0; /* diam^2 -> rad^2 */
+ rad = sqrt(radsq);
+
+ /* Go though all the points again, expanding sphere if necessary */
+ for (ee = 0; ee < npnts; ee++) {
+ double ss;
+ double *vp = pnts[ee];
+
+ /* Compute distance squared of point to bounding shere */
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = vp[f] - p->bcent[f];
+ ss += tt * tt;
+ }
+ if (ss > radsq) {
+ double tt;
+ /* DBG(("Expanding bounding sphere by %f\n",sqrt(ss) - rad)); */
+
+ ss = sqrt(ss) + EPS; /* Radius to point */
+ rad = (rad + ss)/2.0;
+ radsq = rad * rad;
+ tt = ss - rad;
+ for (f = 0; f < fdi; f++)
+ p->bcent[f] = (rad * p->bcent[f] + tt * vp[f])/ss;
+ } else {
+ /* DBG(("Bounding sphere encloses by %f\n",rad - sqrt(ss))); */
+ }
+ }
+ if (fdi >= 3) {
+ /* Establish the minimum and maximum member C squared */
+ for (ee = 0; ee < npnts; ee++) {
+ c = pnts[ee][1] * pnts[ee][1] + pnts[ee][2] * pnts[ee][2];
+ if (c < minc)
+ minc = c;
+ if (c > maxc)
+ maxc = c;
+ }
+ }
+ }
+
+ p->brad = p->bradsq = -1.0;
+ p->maxDlc = -1.0;
+ p->maxDh = p->maxDh_ = -1.0;
+ p->sratio = 1.0;
+ p->Wsratio = s->rev.lchw_sq[2];
+ p->bratio = 1.0;
+ p->Wbratio = s->rev.lchw_sq[2];
+ p->Gc = p->Gc_ = NN_GCMIN;
+
+ /* No weighting */
+ if (!s->rev.lchweighted || fdi < 3) {
+
+ for (i = 0; i < npnts; i++) {
+ desq = 0.0;
+ for (f = 0; f < fdi; f++) {
+ double tt = p->bcent[f] - pnts[i][f];
+ desq += tt * tt;
+ }
+ /* Track maximum euclidean distance */
+ if (desq > p->bradsq)
+ p->bradsq = desq;
+ }
+ p->brad = sqrt(p->bradsq); /* Distance rather than squared */
+
+ /* Weighted */
+ } else {
+ double maxde = -1.0;
+
+ /* Locate member maximum deltaLC and deltaH */
+ for (i = 0; i < npnts; i++) {
+
+ /* Compute delta L squared and delta E squared */
+ {
+ double dl, dasq, dbsq;
+ dl = p->bcent[0] - pnts[i][0];
+ dlsq = dl * dl; /* dl squared */
+ dasq = p->bcent[1] - pnts[i][1];
+ dasq *= dasq;
+ dbsq = p->bcent[2] - pnts[i][2];
+ dbsq *= dbsq;
+
+ dchsq = dasq + dbsq;
+ desq = dlsq + dchsq;
+ }
+
+ /* Add any extra dims */
+ for (f = 3; f < fdi; f++) {
+ double tt = p->bcent[f] - pnts[i][f];
+ dxsq += tt * tt;
+ }
+ desq += dxsq;
+
+ /* Track maximum euclidean distance too */
+ if (desq > p->bradsq)
+ p->bradsq = desq;
+
+ /* compute delta chromanance squared */
+ {
+ /* Compute chromanance of member to group center */
+ c1 = sqrt(p->bcent[1] * p->bcent[1] + p->bcent[2] * p->bcent[2]);
+ c2 = sqrt(pnts[i][1] * pnts[i][1] + pnts[i][2] * pnts[i][2]);
+
+ dc = c1 - c2;
+ dcsq = dc * dc;
+ }
+
+ /* Compute delta hue squared */
+ /* (Hue is simply the orthogonal delta to chromanance in the a*b* plane) */
+ if ((dhsq = dchsq - dcsq) < 0.0)
+ dhsq = 0.0;
+
+ /* Weighted delta extra + luminance + chromanance squared */
+ dlcsq = dxsq + s->rev.lchw_sq[0] * dlsq + s->rev.lchw_sq[1] * dcsq;
+
+ /* Using maxDlc & maxDh is an absolute worst case, but */
+ /* using a more exact approximation to the worst point */
+ /* for a given hue correction factor, doesn't seem to help */
+ /* for HWEIGHT > 1.5 */
+
+ /* Track maximum weighted deltaLC squared */
+ if (dlcsq > p->maxDlc)
+ p->maxDlc = dlcsq;
+
+ /* Track maximum deltaH squared */
+ if (dhsq > p->maxDh)
+ p->maxDh = dhsq;
+ }
+ p->brad = sqrt(p->bradsq); /* Euclidean distance rather than squared */
+ p->maxDh_ = sqrt(p->maxDh);
+
+ /* Pre-calculate center C squared */
+ p->Gc = p->bcent[1] * p->bcent[1] + p->bcent[2] * p->bcent[2];
+ if (p->Gc < NN_GCMIN)
+ p->Gc = NN_GCMIN;
+ p->Gc_ = sqrt(p->Gc);
+
+ /* Calculate hue scale down factor for Group center to smallest member C */
+ /* (This is used to scale point/center to center distance) */
+ if (minc < p->Gc) {
+ p->sratio = sqrt(minc/p->Gc);
+ if (s->rev.lchw_sq[2] > 1.0) /* Slightly improves filter ratio */
+ p->Wsratio = (s->rev.lchw_sq[2] - 1.0) * p->sratio + 1.0;
+ else
+ p->Wsratio = s->rev.lchw_sq[2] * p->sratio;
+ }
+
+ /* Calculate hue scale up factor for Group center to largest member C */
+ /* (This is used to scale point/center to center distance) */
+ /* (For group target, multiply group ->bratio values ??) */
+ if (maxc > p->Gc) {
+ p->bratio = sqrt(maxc/p->Gc);
+ if (s->rev.lchw_sq[2] > 1.0) /* Slightly improves filter ratio */
+ p->Wbratio = (s->rev.lchw_sq[2] - 1.0) * p->bratio + 1.0;
+ else
+ p->Wbratio = s->rev.lchw_sq[2] * p->bratio;
+ }
+ }
+}
+
+/* Return nz if point is within euclidean bounding sphere. */
+/* Also return distance squared in *dist if non-NULL */
+static int nn_insphere(rspl *s, double *dist, nn_grp *p, double *src) {
+ int f, fdi = s->fdi;
+ double desq = 0.0;
- /* Compute the center location and radius of the target cell */
for (f = 0; f < fdi; f++) {
- cc[f] = s->rev.gw[f] * (co[f] + 0.5) + s->rev.gl[f];
- rr += 0.25 * s->rev.gw[f] * s->rev.gw[f];
+ double tt = p->bcent[f] - src[f];
+ desq += tt * tt;
}
- rr = sqrt(rr);
-//printf("~1 fill_nncell() cell ix %d, coord %d %d %d, cent %f %f %f, rad %f\n",
-//ix, co[0], co[1], co[2], cc[0], cc[1], cc[2], rr);
-//printf("~1 total of %d fwd cells\n",gno);
- /* For all the forward cells: */
- for (gp = s->g.a, i = 0; i < gno; gp += s->g.pss, i++) {
- int ee;
- int uil; /* One is under the ink limit */
- double dn, df; /* Nearest and farthest distance of fwd cell values */
+ if (dist != NULL)
+ *dist = desq;
- /* Skip cubes that are on the outside edge of the grid */
- for (e = 0; e < di; e++) {
- if(G_FL(gp, e) == 0) /* At the top edge */
- break;
+ return desq <= p->bradsq;
+}
+
+/* Estimate possible smallest weighted distance of point to group. */
+/* If lgst != NULL, also return the estimated largest possible distance. */
+static double nn_pntgrp_est(rspl *s, double *lgst, nn_grp *p, double *src) {
+ int f, fdi = s->fdi;
+ double dxsq = 0.0, desq, dchsq;
+ double dlsq, dcsq, dhsq;
+ double dc, c1, c2;
+ double Tc; /* Point chromanance squared */
+ double sGrr; /* Min Point to group center diatance squared */
+ double bGrr; /* Max Point to group center diatance squared */
+ double rr; /* Largest member distance squared */
+ double sdist; /* Min. estimated distance squared */
+ double bdist; /* Max.. estimated distance squared */
+ double aratio = 1.0;
+
+ /* If not using LCh weighted distances */
+ if (!s->rev.lchweighted || fdi < 3) {
+
+ desq = 0.0;
+ for (f = 0; f < fdi; f++) {
+ double tt = p->bcent[f] - src[f];
+ desq += tt * tt;
}
- if (e < di) { /* Top edge - skip this cube */
- continue;
+
+ /* Return largest possible distance */
+ if (lgst != NULL) {
+ bdist = sqrt(desq) + p->brad + EPS;
+ *lgst = bdist;
}
- /* Compute the closest and furthest distances of nodes of current cell */
- dn = 1e38, df = 0.0;
- for (uil = ee = 0; ee < (1 << di); ee++) { /* For all grid points in the cube */
- double r;
- float *gt = gp + s->g.fhi[ee]; /* Pointer to cube vertex */
-
- if (!s->limiten || gt[-1] <= s->limitv)
- uil = 1;
+ /* Return min possible distance */
+ sdist = sqrt(desq) - p->brad - EPS;
+ if (sdist < 0.0)
+ sdist = 0.0;
+ return sdist;
- /* Update bounding box for this grid point */
- for (r = 0.0, f = 0; f < fdi; f++) {
- double tt = cc[f] - (double)gt[f];
- r += tt * tt;
- }
-//printf("~1 grid location %f %f %f rad %f\n",gt[0],gt[1],gt[2],sqrt(r));
- if (r < dn)
- dn = r;
- if (r > df)
- df = r;
- }
- /* Skip any fwd cells that are over the ink limit */
- if (!uil)
- continue;
+ /* We're using LCh weighting, so we need to do some adjustments */
+ } else {
+ /* Compute components of weighted distance of point */
+ /* to group center. */
+ {
+ double dl, dasq, dbsq;
+ dl = p->bcent[0] - src[0];
+ dlsq = dl * dl; /* dl squared */
+ dasq = p->bcent[1] - src[1];
+ dasq *= dasq;
+ dbsq = p->bcent[2] - src[2];
+ dbsq *= dbsq;
+
+ dchsq = dasq + dbsq;
+ }
+
+ /* Compute any extra dims */
+ for (f = 3; f < fdi; f++) {
+ double tt = p->bcent[f] - src[f];
+ dxsq += tt * tt;
+ }
+
+ /* compute delta chromanance squared of target to group center */
+ {
+ /* Compute delta chromanance between target point and group center */
+ c1 = p->Gc_;
+ c2 = Tc = src[1] * src[1] + src[2] * src[2];
+ c2 = sqrt(c2);
+ dc = c1 - c2;
+ dcsq = dc * dc;
+ }
+
+ /* Compute delta hue squared of target point to group center */
+ /* (Hue is simply the orthogonal delta to chromanance in the a*b* plane) */
+ if ((dhsq = dchsq - dcsq) < 0.0)
+ dhsq = 0.0;
+
+ /* Weighted values of L and C delta's */
+ dlsq *= s->rev.lchw_sq[0];
+ dcsq *= s->rev.lchw_sq[1];
+
+ /* Most distant member hue delta adjustment factor */
+ aratio = s->rev.lchw_sq[2];
+ if (Tc > p->Gc) {
+ aratio = sqrt(Tc/p->Gc);
+ if (s->rev.lchw_sq[2] > 1.0) /* Slightly improves filter ratio */
+ aratio = (s->rev.lchw_sq[2] - 1.0) * aratio + 1.0;
+ else
+ aratio = s->rev.lchw_sq[2] * aratio;
+ }
- dn = sqrt(dn) - rr;
- df = sqrt(df) + rr;
+ /* Adjusted maximum member distance to group center */
+ rr = sqrt(p->maxDlc + aratio * p->maxDh);
-//printf("~1 checking cell %d, near %f, far %f\n",i,dn,df);
+ /* Return max. possible distance squared */
+ if (lgst != NULL) {
- /* Skip any that have a closest distance larger that the lists */
- /* closest furthest distance. */
- if (dn > clfu) {
-//printf("~1 skipping cell %d, near %f, far %f clfu %f\n",i,dn,df,clfu);
- continue;
+ /* Adjusted weighted max. distance squared of target to group center */
+ bGrr = dxsq + dlsq + dcsq + dhsq * p->Wbratio;
+
+ /* max. possible distance of target to most distant member */
+ bdist = sqrt(bGrr) + rr + EPS;
+ *lgst = bdist;
}
-//printf("~1 adding cell %d\n",i);
- if (rp == NULL) {
- if ((nf = (nncell_nf *) rev_malloc(s, 6 * sizeof(nncell_nf))) == NULL)
- error("rspl malloc failed - nncell_nf list");
- INCSZ(s, 6 * sizeof(nncell_nf));
- if ((rp = (int *) rev_malloc(s, 6 * sizeof(int))) == NULL)
- error("rspl malloc failed - rev.grid entry");
- INCSZ(s, 6 * sizeof(int));
- *rpp = rp;
- rp[0] = 6; /* Allocation */
- rp[1] = 4; /* Next empty cell */
- rp[2] = 1; /* Reference count */
- rp[3] = i;
- nf[3].n = dn;
- nf[3].f = df;
- rp[4] = -1;
- } else {
- int z = rp[1], ll = rp[0];
- if (z >= (ll-1)) { /* Not enough space */
- INCSZ(s, ll * sizeof(nncell_nf));
- INCSZ(s, ll * sizeof(int));
- ll *= 2;
- if ((nf = (nncell_nf *) rev_realloc(s, nf, sizeof(nncell_nf) * ll)) == NULL)
- error("rspl realloc failed - nncell_nf list");
- if ((rp = (int *) rev_realloc(s, rp, sizeof(int) * ll)) == NULL)
- error("rspl realloc failed - rev.grid entry");
- *rpp = rp;
- rp[0] = ll;
- }
- rp[z] = i;
- nf[z].n = dn;
- nf[z++].f = df;
- rp[z] = -1;
- rp[1] = z;
- }
-
- if (df < clfu)
- clfu = df;
- }
-//printf("~1 Current list is:\n");
-//for (e = 3; rp[e] != -1; e++)
-//printf(" %d: Cell %d near %f far %f\n",e,rp[e],nf[e].n,nf[e].f);
-
- /* Now filter out any cells that have a closest point that is further than */
- /* closest furthest point */
- {
- int z, w, ll = rp[0];
+ /* Adjusted weighted min. distance squared of target to group center */
+ sGrr = dxsq + dlsq + dcsq + dhsq * p->Wsratio;
- /* For all the cells in the current list: */
- for (w = z = 3; rp[z] != -1; z++) {
+ /* min. possible distance of target to most distant member */
+ sdist = sqrt(sGrr) - rr - EPS;
+ if (sdist < 0.0)
+ sdist = 0.0;
- /* If the new cell nearest is greater than the existing cell closest, */
- /* then don't omit existing cell from the list. */
- if (clfu >= nf[z].n) {
- rp[w] = rp[z];
- nf[w].n = nf[z].n;
- nf[w].f = nf[z].f;
- w++;
- }
-//else printf("~1 deleting cell %d because %f >= %f\n",rp[z],clfu, nf[z].f);
+ return sdist;
+ }
+}
+
+/* Estimate possible smallest weighted distance of group to group. */
+/* If lgst != NULL, also return the estimated largest possible distance. */
+static double nn_grpgrp_est(rspl *s, double *lgst, nn_grp *p1, nn_grp *p2) {
+ int f, fdi = s->fdi;
+ double dxsq = 0.0, desq, dchsq;
+ double dlsq, dcsq, dhsq;
+ double dc, c1, c2;
+ double sGrr; /* Min Point to group center diatance squared */
+ double bGrr; /* Max Point to group center diatance squared */
+ double rr1, rr2; /* Largest member distance squared */
+ double sdist; /* Min. estimated distance squared */
+ double bdist; /* Max.. estimated distance squared */
+ double aratio1 = 1.0, aratio2 = 1.0;
+
+ /* If not using LCh weighted distances */
+ if (!s->rev.lchweighted || fdi < 3) {
+
+ desq = 0.0;
+ for (f = 0; f < fdi; f++) {
+ double tt = p1->bcent[f] - p2->bcent[f];
+ desq += tt * tt;
+ }
+
+ /* Return largest possible distance */
+ if (lgst != NULL) {
+ bdist = sqrt(desq) + p1->brad + p2->brad + EPS;
+ *lgst = bdist;
}
- rp[w] = rp[z];
+
+ /* Return min possible distance */
+ sdist = sqrt(desq) - p1->brad - p2->brad - EPS;
+ if (sdist < 0.0)
+ sdist = 0.0;
+ return sdist;
+
+ /* We're using LCh weighting, so we need to do some adjustments */
+ } else {
+ double Wratio;
+
+ /* Compute components of weighted distance of group center */
+ /* to group center. */
+ {
+ double dl, dasq, dbsq;
+ dl = p1->bcent[0] - p2->bcent[0];
+ dlsq = dl * dl; /* dl squared */
+ dasq = p1->bcent[1] - p2->bcent[1];
+ dasq *= dasq;
+ dbsq = p1->bcent[2] - p2->bcent[2];
+ dbsq *= dbsq;
+
+ dchsq = dasq + dbsq;
+ }
+
+ /* Compute any extra dims */
+ for (f = 3; f < fdi; f++) {
+ double tt = p1->bcent[f] - p2->bcent[f];
+ dxsq += tt * tt;
+ }
+
+ /* compute delta chromanance squared of point to group center */
+ {
+ /* Compute delta chromanance group centers */
+ c1 = p1->Gc_;
+ c2 = p2->Gc_;
+ dc = c1 - c2;
+ dcsq = dc * dc;
+ }
+
+ /* Compute delta hue squared of group centers */
+ /* (Hue is simply the orthogonal delta to chromanance in the a*b* plane) */
+ if ((dhsq = dchsq - dcsq) < 0.0)
+ dhsq = 0.0;
+
+ /* Weighted values of L and C delta's */
+ dlsq *= s->rev.lchw_sq[0];
+ dcsq *= s->rev.lchw_sq[1];
+
+ /* Most distant member hue delta adjustment factor */
+ aratio1 = aratio2 = s->rev.lchw_sq[2];
+
+ if ((p1->Gc_ + p1->maxDh) > p2->Gc_) {
+ aratio2 = (p1->Gc_ + p1->maxDh)/p2->Gc_;
+ if (s->rev.lchw_sq[2] > 1.0) /* Slightly improves filter ratio */
+ aratio2 = (s->rev.lchw_sq[2] - 1.0) * aratio2 + 1.0;
+ else
+ aratio2 = s->rev.lchw_sq[2] * aratio2;
+
+ }
+ if ((p2->Gc_ + p2->maxDh) > p1->Gc_) {
+ aratio1 = (p2->Gc_ + p2->maxDh)/p1->Gc_;
+ if (s->rev.lchw_sq[2] > 1.0) /* Slightly improves filter ratio */
+ aratio1 = (s->rev.lchw_sq[2] - 1.0) * aratio1 + 1.0;
+ else
+ aratio1 = s->rev.lchw_sq[2] * aratio1;
+ }
+
+ /* Adjusted maximum member distance to group center */
+ rr1 = sqrt(p1->maxDlc + aratio1 * p1->maxDh);
+ rr2 = sqrt(p2->maxDlc + aratio2 * p2->maxDh);
+
+ /* Returne max. possible distance squared */
+ if (lgst != NULL) {
+ if (s->rev.lchw_sq[2] > 1.0) /* Slightly improves filter ratio */
+ Wratio = (s->rev.lchw_sq[2] - 1.0) * p1->bratio * p2->bratio + 1.0;
+ else
+ Wratio = s->rev.lchw_sq[2] * p1->bratio * p2->bratio;
+
+ /* Adjusted weighted max. distance squared of group centers */
+ bGrr = dxsq + dlsq + dcsq + dhsq * Wratio;
+
+ /* max. possible distance of target to most distant member */
+ bdist = sqrt(bGrr) + rr1 + rr2 + EPS;
+ *lgst = bdist;
+ }
+
+ if (s->rev.lchw_sq[2] > 1.0) /* Slightly improves filter ratio */
+ Wratio = (s->rev.lchw_sq[2] - 1.0) * p1->sratio * p2->sratio + 1.0;
+ else
+ Wratio = s->rev.lchw_sq[2] * p1->sratio * p2->sratio;
+
+ /* Adjusted weighted min. distance squared of group centers */
+ sGrr = dxsq + dlsq + dcsq + dhsq * Wratio;
+
+ /* min. possible distance of target to most distant member */
+ sdist = sqrt(sGrr) - rr1 - rr2 - EPS;
+ if (sdist < 0.0)
+ sdist = 0.0;
+
+ return sdist;
}
-//printf("~1 Current list is:\n");
-//for (e = 3; rp[e] != -1; e++)
-//printf(" %d: Cell %d near %f far %f\n",e,rp[e],nf[e].n,nf[e].f);
- free(nf);
-//printf("~1 Done\n");
}
+/* ------------------------------------------------------------ */
+static void fill_nncell(rspl *s, int *co, int ix);
+
/* Return the pointer to the list of nearest fwd cells given */
/* the target output values. The pointer will be to the first */
/* index in the list (ie. list address + 3) */
@@ -1907,21 +2404,39 @@ calc_fwd_nn_cell_list(
for (ix = 0, f = 0; f < fdi; f++) {
double t = (v[f] - s->rev.gl[f])/s->rev.gw[f];
mi[f] = (int)floor(t); /* Grid coordinate */
- if (mi[f] < 0) /* Clip to reverse range, so we always return a result */
+ if (mi[f] < 0) /* Clip to reverse range, so we always return a result */
mi[f] = 0;
else if (mi[f] > rgres_1)
mi[f] = rgres_1;
ix += mi[f] * s->rev.coi[f]; /* Accumulate reverse grid index */
}
+ s->rev.sb->rix = ix; /* Set diagnostic value */
+
rpp = s->rev.nnrev + ix;
if (*rpp == NULL) {
if (s->rev.fastsetup)
- fill_nncell(s, mi, ix);
+ fill_nncell(s, mi, ix); /* Fill on-demand */
if (*rpp == NULL)
rpp = s->rev.rev + ix; /* fall back to in-gamut lookup */
}
- if (*rpp == NULL)
+ if (*rpp == NULL) {
+#ifdef CHECK_NNLU
+ printf("Got NULL list for nearest search, targ %s,\n coord %s, rix %d\n", debPdv(fdi,v),debPiv(fdi,mi),ix);
+ if (ix < 0 || ix >= s->rev.no)
+ printf("Index is outside range 0 .. %d\n",s->rev.no-1);
+ else {
+ if (s->rev.nnrev[ix] == NULL)
+ printf(" nnrev = NULL\n");
+ else
+ printf(" nnrev length = %d\n",s->rev.nnrev[ix][1]-3);
+ if (s->rev.rev[ix] == NULL)
+ printf(" rev = NULL\n");
+ else
+ printf(" rev = length = %d\n",s->rev.rev[ix][1]-3);
+ }
+#endif
return NULL;
+ }
return (*rpp) + 3;
}
@@ -1932,6 +2447,7 @@ static int add_lu_svd(simplex *x);
static int add_locus(schbase *b, simplex *x);
static int add_auxil_lu_svd(schbase *b, simplex *x);
static int within_simplex(simplex *x, double *p);
+static int within_simplex_limit(simplex *x, double *p);
static void simplex_to_abs(simplex *x, double *in, double *out);
static int auxil_solve(schbase *b, simplex *x, double *xp);
@@ -1939,7 +2455,7 @@ static int auxil_solve(schbase *b, simplex *x, double *xp);
/* ---------------------- */
/* Exact search functions */
/* Return non-zero if cell is acceptable */
-static int exact_setsort(schbase *b, cell *c) {
+static int exact_setsort(schbase *b, fxcell *c) {
rspl *s = b->s;
int f, fdi = s->fdi;
double ss;
@@ -1948,11 +2464,11 @@ static int exact_setsort(schbase *b, cell *c) {
/* Check that the target lies within the cell bounding sphere */
for (ss = 0.0, f = 0; f < fdi; f++) {
- double tt = c->bcent[f] - b->v[f];
+ double tt = c->g.bcent[f] - b->v[f];
ss += tt * tt;
}
- if (ss > c->bradsq) {
- DBG(("Cell rejected - %s outside sphere c %s rad %f\n",icmPdv(fdi,b->v),icmPdv(fdi,c->bcent),sqrt(c->bradsq)));
+ if (ss > c->g.bradsq) {
+ DBG(("Cell rejected - %s outside sphere c %s rad %f\n",debPdv(fdi,b->v),debPdv(fdi,c->g.bcent),sqrt(c->g.bradsq)));
return 0;
}
@@ -2019,7 +2535,7 @@ static int exact_compute(schbase *b, simplex *x) {
/* Compute the solution (in simplex space) */
lu_backsub(x->d_u, sdi, (int *)x->d_w, xp);
- /* Check that the solution is within the simplex */
+ /* Check that the solution is within the simplex & meets ink limit */
if ((wsrv = within_simplex(x, xp)) == 0) {
DBG(("Solution rejected because not in simplex\n"));
return 0;
@@ -2068,7 +2584,7 @@ static int exact_compute(schbase *b, simplex *x) {
/* -------------------------- */
/* Auxiliary search functions */
-static int auxil_setsort(schbase *b, cell *c) {
+static int auxil_setsort(schbase *b, fxcell *c) {
rspl *s = b->s;
int f, fdi = b->s->fdi;
int ee, ixc = b->ixc;
@@ -2082,11 +2598,11 @@ static int auxil_setsort(schbase *b, cell *c) {
/* Check that the target lies within the cell bounding sphere */
for (ss = 0.0, f = 0; f < fdi; f++) {
- double tt = c->bcent[f] - b->v[f];
+ double tt = c->g.bcent[f] - b->v[f];
ss += tt * tt;
}
- if (ss > c->bradsq) {
- DBG(("Cell rejected - %s outside sphere c %s rad %f\n",icmPdv(fdi,b->v),icmPdv(fdi,c->bcent),sqrt(c->bradsq)));
+ if (ss > c->g.bradsq) {
+ DBG(("Cell rejected - %s outside sphere c %s rad %f\n",debPdv(fdi,b->v),debPdv(fdi,c->g.bcent),sqrt(c->g.bradsq)));
return 0;
}
@@ -2132,7 +2648,7 @@ static int auxil_setsort(schbase *b, cell *c) {
}
/* Re-check whether it's worth searching cell */
-static int auxil_check(schbase *b, cell *c) {
+static int auxil_check(schbase *b, fxcell *c) {
int ee, ixc = b->ixc, nabove;
DBG(("Reverse auxiliary search, re-check cell\n"));
@@ -2184,11 +2700,11 @@ static int auxil_compute(schbase *b, simplex *x) {
for (f = 0; f <= x->sdi; f++)
sum += x->vix[f];
printf("Simplex of cell ix %d, sum 0x%x, sdi = %d, efdi = %d\n",x->ix, sum, x->sdi, x->efdi);
- printf("Target val %s\n",icmPdv(fdi, b->v));
+ printf("Target val %s\n",debPdv(fdi, b->v));
for (f = 0; f <= x->sdi; f++) {
int ix = x->vix[f], i;
float *fcb = s->g.a + ix * s->g.pss; /* Pointer to base float of fwd cell */
- printf("Simplex vtx %d [cell ix %d] val %s\n",f,ix,icmPfv(fdi, fcb));
+ printf("Simplex vtx %d [cell ix %d] val %s\n",f,ix,debPfv(fdi, fcb));
}
}
#endif
@@ -2242,7 +2758,7 @@ static int auxil_compute(schbase *b, simplex *x) {
/* Convert solution from simplex relative to absolute space */
simplex_to_abs(x, p, xp);
- DBG(("Got solution at %s\n", icmPdv(di,p)));
+ DBG(("Got solution at %s\n", debPdv(di,p)));
//printf("~~ soln = %f %f %f %f\n",p[0],p[1],p[2],p[3]);
//printf("~~ About to compute auxil distance\n");
@@ -2290,7 +2806,7 @@ static int auxil_compute(schbase *b, simplex *x) {
/* ------------------------------------ */
/* Locus range search functions */
-static int locus_setsort(schbase *b, cell *c) {
+static int locus_setsort(schbase *b, fxcell *c) {
rspl *s = b->s;
int f, fdi = s->fdi;
int lxi = b->lxi; /* Auxiliary we are finding min/max of */
@@ -2307,11 +2823,11 @@ static int locus_setsort(schbase *b, cell *c) {
/* Check that the target lies within the cell bounding sphere */
for (ss = 0.0, f = 0; f < fdi; f++) {
- double tt = c->bcent[f] - b->v[f];
+ double tt = c->g.bcent[f] - b->v[f];
ss += tt * tt;
}
- if (ss > c->bradsq) {
- DBG(("Cell rejected - %s outside sphere c %s rad %f\n",icmPdv(fdi,b->v),icmPdv(fdi,c->bcent),sqrt(c->bradsq)));
+ if (ss > c->g.bradsq) {
+ DBG(("Cell rejected - %s outside sphere c %s rad %f\n",debPdv(fdi,b->v),debPdv(fdi,c->g.bcent),sqrt(c->g.bradsq)));
return 0;
}
@@ -2338,7 +2854,7 @@ static int locus_setsort(schbase *b, cell *c) {
}
/* Re-check whether it's worth searching simplexes */
-static int locus_check(schbase *b, cell *c) {
+static int locus_check(schbase *b, fxcell *c) {
int lxi = b->lxi; /* Auxiliary we are finding min/max of */
int ixc = b->ixc;
@@ -2372,12 +2888,12 @@ static int locus_compute(schbase *b, simplex *x) {
for (f = 0; f <= x->sdi; f++)
sum += x->vix[f];
printf("Simplex of cell ix %d, sum 0x%x, sdi = %d, efdi = %d\n",x->ix, sum, x->sdi, x->efdi);
- printf("Target val %s\n",icmPdv(fdi, b->v));
+ printf("Target val %s\n",debPdv(fdi, b->v));
for (f = 0; f <= x->sdi; f++) {
int ix = x->vix[f], i;
float *fcb = s->g.a + ix * s->g.pss; /* Pointer to base float of fwd cell */
double v[MXDO];
- printf("Simplex vtx %d [cell ix %d] val %s\n",f,ix,icmPfv(fdi, fcb));
+ printf("Simplex vtx %d [cell ix %d] val %s\n",f,ix,debPfv(fdi, fcb));
}
}
#endif
@@ -2419,7 +2935,7 @@ static int locus_compute(schbase *b, simplex *x) {
/* ------------------- */
/* Vector clipping search functions */
-static int clipv_setsort(schbase *b, cell *c) {
+static int clipv_setsort(schbase *b, fxcell *c) {
rspl *s = b->s;
int f, fdi = s->fdi;
double ss, dp;
@@ -2431,7 +2947,7 @@ static int clipv_setsort(schbase *b, cell *c) {
/* First compute dot product cdir . (bcent - v) */
/* == distance to center of sphere in direction of clip vector */
for (dp = 0.0, f = 0; f < fdi; f++) {
- dp += b->ncdir[f] * (c->bcent[f] - b->v[f]);
+ dp += b->ncdir[f] * (c->g.bcent[f] - b->v[f]);
}
if (s->limiten != 0 && c->limmin > s->limitv) {
@@ -2442,12 +2958,12 @@ static int clipv_setsort(schbase *b, cell *c) {
//printf("~~ dot product = %f\n",dp);
/* Now compute closest distance to sphere center */
for (ss = 0.0, f = 0; f < fdi; f++) {
- double tt = b->v[f] + dp * b->ncdir[f] - c->bcent[f];
+ double tt = b->v[f] + dp * b->ncdir[f] - c->g.bcent[f];
ss += tt * tt;
}
//printf("~~ distance to sphere center = %f\n",sqrt(ss));
- if (ss > c->bradsq) {
+ if (ss > c->g.bradsq) {
DBG(("Cell is rejected - wrong direction or bounding sphere\n"));
return 0;
}
@@ -2462,7 +2978,7 @@ static int clipv_setsort(schbase *b, cell *c) {
/* because we assume that nothing will set a small cdist */
/* before the search commences (unlike auxil). */
/* Note that line search loop exits on finding any solution. */
-static int clipv_check(schbase *b, cell *c) {
+static int clipv_check(schbase *b, fxcell *c) {
DBG(("Reverse clipping re-check\n"));
@@ -2471,12 +2987,12 @@ static int clipv_check(schbase *b, cell *c) {
double dist;
/* Compute a conservative "best possible solution clip distance" */
for (dist = 0.0, f = 0; f < fdi ; f++) {
- double tt = (c->bcent[f] - b->v[f]);
+ double tt = (c->g.bcent[f] - b->v[f]);
dist += tt * tt;
}
dist = sqrt(dist); /* Target distance to bounding */
- if (dist >= (c->brad + b->cdist)) { /* Equal or worse clip solution */
+ if (dist >= (c->g.brad + b->cdist)) { /* Equal or worse clip solution */
DBG(("Cell best possible solution worse than current\n"));
return 0;
}
@@ -2533,86 +3049,107 @@ static int clipv_compute(schbase *b, simplex *x) {
}
/* ------------------- */
-/* Nearest clipping search functions */
-static int clipn_setsort(schbase *b, cell *c) {
+/* Nearest clipping search functions. */
+/* We use weighted distances if lchweighted. */
+static int clipn_setsort(schbase *b, fxcell *c) {
rspl *s = b->s;
int f, fdi = s->fdi;
double ss;
- DBG(("Reverse nearest clipping search evaluate cell\n"));
+ DBG(("Reverse nearest clipping search evaluate fwd cell ix %d\n",c->ix));
+//if (b->rix == 7135) printf("Reverse nearest clipping search evaluate fwd cell ix %d\n",c->ix);
- /* Compute a conservative "best possible solution clip distance" */
- for (ss = 0.0, f = 0; f < fdi ; f++) {
- double tt = (c->bcent[f] - b->v[f]);
- ss += tt * tt;
- }
- ss = sqrt(ss); /* Target distance to bounding sphere */
- ss -= c->brad;
- if (ss < 0.0)
- ss = 0.0;
+ /* Compute an estimated weighted clip distance from target point to this fxcell */
+ ss = nn_pntgrp_est(s, NULL, &c->g, b->v);
/* Check that the cell could possibly improve the solution */
if (b->cdist < INF_DIST) { /* If some clip solution has been found */
if (ss >= b->cdist) { /* Equal or worse clip solution */
DBG(("Cell best possible solution worse than current\n"));
+
+//if (b->rix == 7135) {
+// printf("Cell best possible solution worse than current\n");
+// printf("current dist %f, best to fwd %f\n",b->cdist,ss);
+//}
return 0;
}
}
if (s->limiten != 0 && c->limmin > s->limitv) {
DBG(("Cell is rejected - ink limit, min = %f, limit = %f\n",c->limmin,s->limitv));
+//if (b->rix == 7135) printf("Cell is rejected - ink limit, min = %f, limit = %f\n",c->limmin,s->limitv);
return 0;
}
- c->sort = ss; /* May be -ve if beyond clip target point ? */
+ c->sort = ss;
- DBG(("Cell is accepted\n"));
+ DBG(("Cell is accepted (%f < %f)\n",ss,b->cdist));
+//if (b->rix == 7135) printf("Cell is accepted (%f < %f)\n",ss,b->cdist);
return 1;
}
/* Clipping check functions */
-static int clipn_check(schbase *b, cell *c) {
+static int clipn_check(schbase *b, fxcell *c) {
- DBG(("Reverse nearest clipping re-check\n"));
+ DBG(("Reverse nearest clipping re-check fwd cell ix %d\n",c->ix));
+//if (b->rix == 7135) printf("Reverse nearest clipping re-check fwd cell ix %d\n",c->ix);
if (b->cdist < INF_DIST) { /* If some clip solution has been found */
/* re-use sort value, best possible distance to solution */
if (c->sort >= b->cdist) { /* Equal or worse clip solution */
- DBG(("Cell best possible solution worse than current\n"));
+ DBG(("Cell best possible solution now worse than current\n"));
+//if (b->rix == 7135) {
+// printf("Cell best possible solution now worse than current\n");
+// printf("current dist %f, best to fwd %f\n",b->cdist,c->sort);
+//}
return 0;
}
}
DBG(("Cell is still ok\n"));
+//if (b->rix == 7135) printf("Cell is still ok\n");
return 1;
}
+static int lchw_nnearest_clip_solve(schbase *b, simplex *x, double *xp, double *xv, double *err);
static int nnearest_clip_solve(schbase *b, simplex *x, double *xp, double *xv, double *err);
/* Compute a clip solution */
static int clipn_compute(schbase *b, simplex *x) {
rspl *s = b->s;
int f, fdi = s->fdi;
- datai p; /* Input space solution */
- datao v; /* Output space solution */
- double err; /* output error of solution */
- int wsrv; /* Within simplex return value */
+ datai p; /* Simplex input space solution */
+ datao v; /* Output space solution */
+ double err; /* output error of solution */
+ int wsrv; /* Within simplex return value */
- DBG(("Clipn: computing possible solution simplex %d, sdi = %d, efdi = %d\n",x->si,x->sdi,x->efdi));
+ DBG(("Clipn: computing possible solution cell %d, simplex %d, sdi = %d, efdi = %d\n",x->ix,x->si,x->sdi,x->efdi));
+//if (b->rix == 7135) printf("Clipn: computing possible solution cell %d, simplex %d, sdi = %d, efdi = %d\n",x->ix,x->si,x->sdi,x->efdi);
/* Compute a solution value */
- if ((wsrv = nnearest_clip_solve(b, x, p, v, &err)) == 0) {
- DBG(("Doesn't contain a solution\n"));
- return 0;
+ if (s->rev.lchweighted) {
+ if ((wsrv = lchw_nnearest_clip_solve(b, x, p, v, &err)) == 0) {
+ DBG(("Doesn't contain a solution\n"));
+//if (b->rix == 7135) printf("Doesn't contain a solution\n");
+ return 0;
+ }
+ } else {
+ if ((wsrv = nnearest_clip_solve(b, x, p, v, &err)) == 0) {
+ DBG(("Doesn't contain a solution\n"));
+//if (b->rix == 7135) printf("Doesn't contain a solution\n");
+ return 0;
+ }
}
/* We want the smallest clip error */
if (err >= b->cdist) { /* Equal or worse clip solution */
- DBG(("better solution has been found before\n"));
+ DBG(("better solution has been found before (%f < %f)\n",b->cdist,err));
+//if (b->rix == 7135) printf("better solution has been found before (%f < %f)\n",b->cdist,err);
return 0;
}
- DBG(("######## Accepting new clipn solution with error %f\n",err));
+ DBG(("######## Accepting new clipn solution with error %f (replaces %f)\n",err,b->cdist));
+//if (b->rix == 7135) printf("######## Accepting new clipn solution with error %f (replaces %f)\n",err,b->cdist);
simplex_to_abs(x, b->cpp[0].p, p); /* Convert to abs. space & copy */
@@ -2646,7 +3183,7 @@ double *xp /* Return solution xp[sdi] */
int f, efdi = x->efdi;
int dof = sdi-efdi; /* Degree of freedom of simplex locus */
int *icomb = x->psxi->icomb; /* abs -> simplex coordinate translation */
- double auxt[MXRI]; /* Simplex relative auxiliary targets */
+ double auxt[MXRI]; /* Simplex relative auxiliary targets */
double bb[MXRI];
int wsrv; /* Within simplex return value */
@@ -2667,8 +3204,9 @@ double *xp /* Return solution xp[sdi] */
/* Compute the solution (in simplex space) */
lu_backsub(x->d_u, sdi, (int *)x->d_w, xp);
+ /* Check that the solution is within the simplex & meets ink limit */
if ((wsrv = within_simplex(x, xp)) != 0) {
- DBG(("Got solution at %s\n", icmPdv(sdi,xp)));
+ DBG(("Got solution at %s\n", debPdv(sdi,xp)));
return wsrv; /* OK, got solution */
}
@@ -2708,8 +3246,9 @@ double *xp /* Return solution xp[sdi] */
for (e = 0; e < sdi; e++) {
xp[e] = x->lo_bd[e] + tt * x->lo_l[e][0];
}
+ /* Check that the solution is within the simplex & meets ink limit */
if ((wsrv = within_simplex(x, xp)) != 0) {
- DBG(("Got solution %s\n",icmPdv(di,xp)));
+ DBG(("Got solution %s\n",debPdv(di,xp)));
return wsrv; /* OK, got solution */
}
DBG(("No solution (not within simplex)\n"));
@@ -2755,8 +3294,9 @@ double *xp /* Return solution xp[sdi] */
xp[e] = x->lo_bd[e] + tt;
}
+ /* Check that the solution is within the simplex & meets ink limit */
if ((wsrv = within_simplex(x, xp)) != 0) {
- DBG(("Got solution %s\n",icmPdv(di,xp)));
+ DBG(("Got solution %s\n",debPdv(di,xp)));
return wsrv; /* OK, got solution */
}
DBG(("No solution (not within simplex)\n"));
@@ -2793,7 +3333,7 @@ simplex *x
/* Compute the solution (in simplex space) */
lu_backsub(x->d_u, sdi, (int *)x->d_w, pp);
- /* Check that the solution is within the simplex */
+ /* Check that the solution is within the simplex & meets ink limit */
if ((wsrv = within_simplex(x, pp)) != 0) {
double xval;
int lxi = b->lxi; /* Auxiliary we are finding min/max of (Abs space) */
@@ -2913,11 +3453,11 @@ double *err /* Output error distance at solution point */
return 0; /* No solution */
}
- /* Check that the solution is within the simplex */
+ /* Check that the solution is within the simplex & meets ink limit */
if ((wsrv = within_simplex(x, tb)) != 0) {
double dist; /* distance to clip target */
- DBG(("Got solution within simplex %s\n", icmPdv(sdi,tb)));
+ DBG(("Got solution within simplex %s\n", debPdv(sdi,tb)));
/* Compute the output space solution point */
for (f = 0; f < fdi; f++) {
@@ -2932,6 +3472,9 @@ double *err /* Output error distance at solution point */
for (e = 0; e < sdi; e++)
xp[e] = tb[e];
+ // ~~~ are we properly checking if the intersection is
+ // ~~~ backwards rather than forwards in the line direction ?
+
/* Compute distance to clip target */
for (dist = 0.0, f = 0; f < fdi ; f++) {
double tt = (b->v[f] - xv[f]);
@@ -2952,7 +3495,7 @@ double *err /* Output error distance at solution point */
/* - - - - - - - - - - - - - - - - - - - - - - - */
/* Find the point on the simplexes valid surface, that is closest */
-/* to the target output value. */
+/* to the target output value, for the linear (unweighted) case. */
/* We expect to be given a sub simplex with sdi = fdi-1, and efdi = fdi */
/* or a limit sub-simplex with sdi = fdi, and efdi = fdi+1 */
/* Return zero if solution canot be calculated, */
@@ -2963,7 +3506,7 @@ schbase *b,
simplex *x,
double *xp, /* Return solution (simplex parameter space) */
double *xv, /* Return solution (output space) */
-double *err /* Output error distance at solution point */
+double *err /* Output error (weighted) distance at solution point */
) {
rspl *s = b->s;
int e, sdi = x->sdi;
@@ -2977,14 +3520,17 @@ double *err /* Output error distance at solution point */
if (sdi == 0) { /* Solution is vertex */
wsrv = 1;
for (f = 0; f < efdi; f++)
- xv[f] = x->v[sdi][f]; /* Copy vertex value */
- if (x->v[sdi][fdi] > s->limitv) {
+ xv[f] = x->v[0][f]; /* Copy vertex value */
+ if (x->v[0][fdi] > s->limitv) {
if (s->limiten) /* Needed when limiten == 0 */
return 0; /* Over ink limit - no good */
wsrv = 2; /* Would be over */
}
- DBG(("Got assumed vertex solution\n"));
+ DBG(("Got assumed vertex solution (vtx ix %d)\n",x->vix[0]));
+
+ /* General linear nearest solver */
} else {
+
#ifdef NEVER /* Don't specialise ink limit version - use INKSCALE fudge instead */
if (!(x->flags & SPLX_CLIPSX)) { /* Not an ink limited plane simplex */
@@ -3002,22 +3548,24 @@ double *err /* Output error distance at solution point */
/* Find least squares solution */
svdbacksub(x->d_u, x->d_w, x->d_v, tb, tb, efdi, sdi);
- /* Check that the solution is within the simplex */
+ /* Check that the solution is within the simplex & meets ink limit */
if ((wsrv = within_simplex(x, tb)) == 0) {
DBG(("Nearest clip solution not in simplex\n"));
return 0; /* No solution */
}
- DBG(("Got solution within simplex %s\n",icmPdv(sdi,tb)));
+ DBG(("Got solution within simplex %s\n",debPdv(sdi,tb)));
+//if (b->rix == 7135) printf("Got solution within simplex params %s\n",debPdv(sdi,tb));
+//if (b->rix == 7135) printf(" verticies ix %s\n",debPiv(sdi+1,x->vix));
/* Compute the output space solution point */
for (f = 0; f < fdi; f++) {
double tt = 0.0;
- for (e = 0; e < sdi; e++) {
+ for (e = 0; e < sdi; e++)
tt += (x->v[e][f] - x->v[e+1][f]) * tb[e];
- }
xv[f] = tt + x->v[sdi][f];
}
+//if (b->rix == 7135) printf("Computed Got simplex solution %s\n",debPdv(fdi,xv));
#ifdef NEVER /* ~~1 Haven't figured out equations to make this a special case. */
/* Content to use INKSCALE fudge and rely on SVD least squares. */
} else {
@@ -3031,21 +3579,22 @@ double *err /* Output error distance at solution point */
}
#endif
+
+ /* Copy to return array */
+ for (e = 0; e < sdi; e++)
+ xp[e] = tb[e];
}
- /* Copy to return array */
- for (e = 0; e < sdi; e++)
- xp[e] = tb[e];
+ /* Compute weighted distance to clip target */
+ dist = sqrt(lchw_sq(s, b->v, xv));
+
+//if (b->rix == 7135 && dist < b->cdist) {
+// printf("Got dist %f from %s -> %s with weight %d, %s\n", dist,debPdv(fdi,b->v),debPdv(fdi,xv),s->rev.lchweighted,debPdv(fdi,s->rev.lchw)); }
- /* Compute distance to clip target */
- for (dist = 0.0, f = 0; f < fdi ; f++) {
- double tt = (b->v[f] - xv[f]);
- dist += tt * tt;
- }
DBGV(("Nearest clip output soln: ",fdi," %f", xv, "\n"));
- /* Return the solution in xp[]m xv[] and *err */
- *err = sqrt(dist);
+ /* Return the solution in xp[], xv[] and *err */
+ *err = dist;
DBG(("Nearest clip returning a solution with error %f\n",*err));
return wsrv;
@@ -3054,7 +3603,7 @@ double *err /* Output error distance at solution point */
#ifdef NEVER
/* Utility to convert an implicit ink limit plane equation */
-/* (held at the end of the simplex output value equations), */
+/* held at the end of the simplex output value equations), */
/* into a parameterized surface equation. */
static void
compute_param_limit_surface(
@@ -3149,7 +3698,869 @@ double de[MXRO] /* Delta */
#endif
+/* -------------------------------------------------------- */
+static int lchw_edge_solve(rspl *s, double *vv, double *p, double *vt, double v[MXRI+1][MXRO+1]);
+static int lchw_tri_solve(rspl *s, double *vv, double *p, double *vt, double v[MXRI+1][MXRO+1]);
+
+/* Find the point on the simplexes valid surface, that is closest */
+/* to the target output value, for the LCh weighted case. */
+/* We use Newton itteration to solve this for the 1D (line) and 2D (triangle) */
+/* cases, and explicitly decode the ink limit surfaces back to point, line */
+/* and triangled cases. */
+/* We expect to be given a sub simplex with sdi = 0..2, and efdi = fdi */
+/* or a limit sub-simplex with sdi = 1..3, and efdi = fdi+1 */
+/* We bail with an assert if we get more than 2D to solve. */
+/* Return zero if solution canot be calculated, */
+/* return 1 normally, 2 if solution would be above the (disabled) ink limit */
+static int
+lchw_nnearest_clip_solve(
+schbase *b,
+simplex *x,
+double *xp, /* Return solution (simplex parameter space) */
+double *xv, /* Return solution (output space) */
+double *err /* Output error (weighted) distance at solution point */
+) {
+ rspl *s = b->s;
+ int e, ee, sdi = x->sdi;
+ int f, fdi = s->fdi, efdi = x->efdi;
+ double tb[MXRO]; /* RHS & Parameter solution */
+ double dist; /* distance to clip target */
+ int wsrv = 0; /* Within simplex return value */
+
+ DBG(("LChw nearest clip solution called, cell %d, splx %d\n", x->ix, x->si));
+
+ /* - - - - - - - */
+ if (sdi == 0) { /* Solution is vertex */
+ wsrv = 1;
+ for (f = 0; f < efdi; f++)
+ xv[f] = x->v[0][f]; /* Copy vertex value */
+ if (x->v[0][fdi] > s->limitv) {
+ if (s->limiten) /* Needed when limiten == 0 */
+ return 0; /* Over ink limit - no good */
+ wsrv = 2; /* Would be over */
+ }
+ DBG(("Got assumed vertex solution (vtx ix %d)\n",x->vix[0]));
+
+ /* - - - - - - - */
+ /* Ink limit simplex case */
+ } else if (efdi == (fdi+1)) {
+
+ /* Convert line into vertex and return it */
+ if (sdi == 1) {
+ wsrv = 1;
+
+ /* Ink limit plane point along line */
+ xp[0] = (s->limitv - x->v[1][fdi])/(x->v[0][fdi] - x->v[1][fdi]);
+
+ /* Output value at that point */
+ for (f = 0; f < fdi; f++)
+ xv[f] = (x->v[0][f] - x->v[1][f]) * xp[0] + x->v[1][f];
+
+ DBG(("Got ink limit point on edge\n"));
+
+ /* Turn triangle into line and solve line. */
+ } else if (sdi == 2) {
+ int pos = 0, neg = 0;
+ int ix[MXRI+1]; /* Odd index and the two other indexes */
+ double p[MXRI+1], pp[MXRI+1];
+ double v[MXRI+1][MXRO+1];
+
+ /* Count ink limit signs of vertexes */
+ for (e = 0; e <= sdi; e++) {
+ ix[e] = e;
+ if (x->v[e][fdi] > s->limitv)
+ pos++;
+ else
+ neg++;
+ }
+
+ /* We expect one vertex to be on the other side of the */
+ /* ink limit to the two others. */
+ if (pos == 0 || neg == 0)
+ error("Ink limit tri doesn't have one opposite sign");
+
+ /* Make the first ix be the odd one */
+ if (pos == 1) {
+ if (x->v[0][fdi] <= s->limitv) {
+ if (x->v[1][fdi] > s->limitv) {
+ ix[0] = 1;
+ ix[1] = 0;
+ } else {
+ ix[0] = 2;
+ ix[2] = 0;
+ }
+ }
+ } else {
+ if (x->v[0][fdi] > s->limitv) {
+ if (x->v[1][fdi] <= s->limitv) {
+ ix[0] = 1;
+ ix[1] = 0;
+ } else {
+ ix[0] = 2;
+ ix[2] = 0;
+ }
+ }
+ }
+
+ /* Compute the points on the two edges that cross the ink limit. */
+ /* i.e. for edges ix 0..1 & 0..2 */
+ pp[0] = (s->limitv - x->v[ix[1]][fdi])/(x->v[ix[0]][fdi] - x->v[ix[1]][fdi]);
+ pp[1] = (s->limitv - x->v[ix[2]][fdi])/(x->v[ix[0]][fdi] - x->v[ix[2]][fdi]);
+ for (f = 0; f < fdi; f++) {
+ v[0][f] = (x->v[ix[0]][f] - x->v[ix[1]][f]) * pp[0] + x->v[ix[1]][f];
+ v[1][f] = (x->v[ix[0]][f] - x->v[ix[2]][f]) * pp[1] + x->v[ix[2]][f];
+ }
+
+ /* Solve it */
+ if ((wsrv = lchw_edge_solve(s, xv, p, b->v, v)) != 0) {
+
+ /* Figure out the solution simplex coords */
+ /* (p is weighting of lower indexes vertex) */
+
+ /* Convert solution simplex coords into baricentric weighting */
+ p[1] = 1.0 - p[0];
+
+ /* Sum baricentric weightings for each vertex */
+ for (e = 0; e <= sdi; e++)
+ xp[e] = 0.0;
+
+ xp[ix[0]] += pp[0] * p[0];
+ xp[ix[1]] += (1.0 - pp[0]) * p[0];
+ xp[ix[0]] += pp[1] * p[1];
+ xp[ix[2]] += (1.0 - pp[1]) * p[1];
+
+ /* Convert back to simplex coords */
+ xp[1] = 1.0 - xp[2];
+ xp[0] = xp[0];
+
+ DBG(("Got ink limit edge in triangle\n"));
+ }
+
+ /* Turn tetrahedron into one or two triangles */
+ /* and solve triangles. */
+ } else if (sdi == 3) {
+ int pos = 0, neg = 0;
+ int ix[MXRI+1]; /* Odd index and the three other indexes or 2 + 2 */
+ double p[MXRI+1], pp[MXRI+1];
+ double v[MXRI+1][MXRO+1];
+
+ /* Count ink limit signs of vertexes */
+ for (e = 0; e <= sdi; e++) {
+ ix[e] = e;
+ if (x->v[e][fdi] > s->limitv)
+ pos++;
+ else
+ neg++;
+ }
+
+ /* We expect one or two vertexes t be on the other side of the */
+ /* ink limit to the two others. */
+ if (pos == 0 || neg == 0)
+ error("Ink limit tetrahedron doesn't have one opposite sign");
+
+ /* If we can decompose this into a single triangle */
+ if (pos == 1 || neg == 1) {
+
+ /* Make the first ix be the odd one */
+ for (e = 0; e <= sdi; e++) {
+ if ((pos == 1 && x->v[e][fdi] > s->limitv)
+ || (neg == 1 && x->v[e][fdi] <= s->limitv)) {
+ int tt = ix[0];
+ ix[0] = e;
+ ix[e] = tt;
+ break;
+ }
+ }
+
+ /* Compute the points on the three edges that cross the ink limit. */
+ /* i.e. for edges ix 0..1, 0..2 & 0..3 */
+ pp[0] = (s->limitv - x->v[ix[1]][fdi])/(x->v[ix[0]][fdi] - x->v[ix[1]][fdi]);
+ pp[1] = (s->limitv - x->v[ix[2]][fdi])/(x->v[ix[0]][fdi] - x->v[ix[2]][fdi]);
+ pp[2] = (s->limitv - x->v[ix[3]][fdi])/(x->v[ix[0]][fdi] - x->v[ix[3]][fdi]);
+ for (f = 0; f < fdi; f++) {
+ v[0][f] = (x->v[ix[0]][f] - x->v[ix[1]][f]) * pp[0] + x->v[ix[1]][f];
+ v[1][f] = (x->v[ix[0]][f] - x->v[ix[2]][f]) * pp[1] + x->v[ix[2]][f];
+ v[2][f] = (x->v[ix[0]][f] - x->v[ix[3]][f]) * pp[2] + x->v[ix[3]][f];
+ }
+
+ /* Solve it */
+ if ((wsrv = lchw_tri_solve(s, xv, p, b->v, v)) != 0) {
+
+ /* Figure out the solution simplex coords */
+ /* (p is weighting of lower indexes vertex) */
+
+ /* Convert solution simplex coords into baricentric weighting */
+ p[2] = 1.0 - p[1];
+ p[1] = p[1] - p[0];
+ p[0] = p[0];
+
+ /* Sum baricentric weightings for each vertex */
+ for (e = 0; e <= sdi; e++)
+ xp[e] = 0.0;
+
+ xp[ix[0]] += pp[0] * p[0];
+ xp[ix[1]] += (1.0 - pp[0]) * p[0];
+ xp[ix[0]] += pp[1] * p[1];
+ xp[ix[2]] += (1.0 - pp[1]) * p[1];
+ xp[ix[0]] += pp[2] * p[2];
+ xp[ix[3]] += (1.0 - pp[2]) * p[2];
+
+ /* Convert back to simplex coords */
+ xp[2] = 1.0 - xp[3];
+ xp[1] = xp[1] + xp[0];
+ xp[0] = xp[0];
+
+ DBG(("Got single ink limit triangle in tetrahedron\n"));
+ }
+
+ /* We need to decompose this into two triangles */
+ } else {
+ int wsrv2 = 0;
+ double dist2;
+ double xv2[MXRO]; /* 2nd triangle solution */
+
+ /* Make the first two ix's be the same, leaving second two the same. */
+ for (e = 1; e <= sdi; e++) {
+ if (x->v[0][fdi] > s->limitv && x->v[e][fdi] > s->limitv) {
+ int tt = ix[1];
+ ix[1] = e;
+ ix[e] = tt;
+ break;
+ }
+ }
+
+ /* We choose disjoint vertex pairs as the common edge of the two */
+ /* triangles, and then use each of the remaining pairs to form */
+ /* the other edges. */
+ /* i.e. common edge 0..2 + 1..3, then add 0..3 then 1..2 */
+ pp[0] = (s->limitv - x->v[ix[2]][fdi])/(x->v[ix[0]][fdi] - x->v[ix[2]][fdi]);
+ pp[1] = (s->limitv - x->v[ix[3]][fdi])/(x->v[ix[1]][fdi] - x->v[ix[3]][fdi]);
+ pp[2] = (s->limitv - x->v[ix[3]][fdi])/(x->v[ix[0]][fdi] - x->v[ix[3]][fdi]);
+ for (f = 0; f < fdi; f++) {
+ v[0][f] = (x->v[ix[0]][f] - x->v[ix[2]][f]) * pp[0] + x->v[ix[2]][f];
+ v[1][f] = (x->v[ix[1]][f] - x->v[ix[3]][f]) * pp[1] + x->v[ix[3]][f];
+ v[2][f] = (x->v[ix[0]][f] - x->v[ix[3]][f]) * pp[2] + x->v[ix[3]][f];
+ }
+
+ /* Solve first one */
+ if ((wsrv = lchw_tri_solve(s, xv, p, b->v, v)) != 0) {
+
+ dist = sqrt(lchw_sq(s, b->v, xv));
+
+ /* Figure out the solution simplex coords */
+ /* (p is weighting of lower indexes vertex) */
+
+ /* Convert solution simplex coords into baricentric weighting */
+ p[2] = 1.0 - p[1];
+ p[1] = p[1] - p[0];
+ p[0] = p[0];
+
+ /* Sum baricentric weightings for each vertex */
+ for (e = 0; e <= sdi; e++)
+ xp[e] = 0.0;
+
+ xp[ix[0]] += pp[0] * p[0];
+ xp[ix[2]] += (1.0 - pp[0]) * p[0];
+ xp[ix[1]] += pp[1] * p[1];
+ xp[ix[3]] += (1.0 - pp[1]) * p[1];
+ xp[ix[0]] += pp[2] * p[2];
+ xp[ix[3]] += (1.0 - pp[2]) * p[2];
+
+ /* Convert back to simplex coords */
+ xp[2] = 1.0 - xp[3];
+ xp[1] = xp[1] + xp[0];
+ xp[0] = xp[0];
+ }
+
+ /* Setup other triangle, 0..2 + 1..3, with 1..2 */
+ pp[0] = (s->limitv - x->v[ix[2]][fdi])/(x->v[ix[0]][fdi] - x->v[ix[2]][fdi]);
+ pp[1] = (s->limitv - x->v[ix[3]][fdi])/(x->v[ix[1]][fdi] - x->v[ix[3]][fdi]);
+ pp[2] = (s->limitv - x->v[ix[2]][fdi])/(x->v[ix[1]][fdi] - x->v[ix[2]][fdi]);
+ for (f = 0; f < fdi; f++) {
+ v[0][f] = (x->v[ix[0]][f] - x->v[ix[2]][f]) * pp[0] + x->v[ix[2]][f];
+ v[1][f] = (x->v[ix[1]][f] - x->v[ix[3]][f]) * pp[1] + x->v[ix[3]][f];
+ v[2][f] = (x->v[ix[1]][f] - x->v[ix[2]][f]) * pp[2] + x->v[ix[2]][f];
+ }
+
+ /* Solve second triangle */
+ if ((wsrv2 = lchw_tri_solve(s, xv2, p, b->v, v)) != 0) {
+
+ dist2 = sqrt(lchw_sq(s, b->v, xv));
+
+ /* Use this second solution */
+ if (wsrv == 0 || dist2 < dist) {
+
+ dist = dist2;
+
+ /* Figure out the solution simplex coords */
+ /* (p is weighting of lower indexes vertex) */
+
+ /* Convert solution simplex coords into baricentric weighting */
+ p[2] = 1.0 - p[1];
+ p[1] = p[1] - p[0];
+ p[0] = p[0];
+
+ /* Sum baricentric weightings for each vertex */
+ for (e = 0; e <= sdi; e++)
+ xp[e] = 0.0;
+
+ xp[ix[0]] += pp[0] * p[0];
+ xp[ix[2]] += (1.0 - pp[0]) * p[0];
+ xp[ix[1]] += pp[1] * p[1];
+ xp[ix[3]] += (1.0 - pp[1]) * p[1];
+ xp[ix[1]] += pp[2] * p[2];
+ xp[ix[2]] += (1.0 - pp[2]) * p[2];
+
+ /* Convert back to simplex coords */
+ xp[2] = 1.0 - xp[3];
+ xp[1] = xp[1] + xp[0];
+ xp[0] = xp[0];
+
+ for (f = 0; f < fdi; f++)
+ xv[f] = xv2[f];
+
+ } else {
+ wsrv2 = 0;
+ }
+ }
+
+#ifdef DEBUG
+ if (wsrv2)
+ DBG(("Got second ink limit triangle in tetrahedron\n"));
+ else if (wsrv)
+ DBG(("Got first ink limit triangle in tetrahedron\n"));
+#endif
+ *err = dist;
+ return wsrv;
+ }
+ } else {
+ error("rev: lchw_nnearest_clip_solve sdi = %d\n",sdi);
+ }
+
+ /* All solutions computed on the ink limit surface */
+ /* are assumed to be valid */
+
+ /* - - - - - - - */
+ /* Non-ink limit simplex case */
+ } else {
+
+ /* Line */
+ if (sdi == 1) {
+ wsrv = lchw_edge_solve(s, xv, xp, b->v, x->v);
+
+ DBG(("Got line solution\n"));
+
+ /* Triangle */
+ } else if (sdi == 2) {
+ wsrv = lchw_tri_solve(s, xv, xp, b->v, x->v);
+
+ DBG(("Got triangle solution\n"));
+
+ /* Oops */
+ } else {
+ error("rev: lchw_nnearest_clip_solve sdi = %d\n",sdi);
+ }
+
+ /* Check that the result is within the ink limit */
+ if (wsrv != 0)
+ wsrv = within_simplex_limit(x, xp);
+ }
+
+ if (wsrv == 0)
+ return wsrv;
+
+ /* Compute weighted distance to clip target */
+ dist = sqrt(lchw_sq(s, b->v, xv));
+
+ DBGV(("LChw nearest clip output soln: ",fdi," %f", xv, "\n"));
+
+ /* Return the solution in xp[], xv[] and *err */
+ *err = dist;
+
+ DBG(("LChw nearest clip returning a solution with error %f\n",*err));
+
+#ifdef NEVER
+ {
+ double chxv[MXRO];
+
+ printf("LChw nearest clip returning a solution with error %f\n",dist);
+
+ printf("Solution (sx in) %s -> out %s\n", debPdv(sdi, xp), debPdv(fdi, xv));
+
+ if (dist < b->cdist) { /* Equal or worse clip solution */
+ printf("Will be new best solution\n");
+ }
+
+ /* Check the output space solution point */
+ for (f = 0; f < fdi; f++) {
+ double tt = 0.0;
+ for (e = 0; e < sdi; e++)
+ tt += (x->v[e][f] - x->v[e+1][f]) * xp[e];
+ chxv[f] = tt + x->v[sdi][f];
+ }
+ for (f = 0; f < fdi; f++) {
+ if (fabs(chxv[f] - xv[f]) > 1e-3) {
+ break;
+ }
+ }
+ if (f < fdi)
+ printf(" ###### Check of out failed: %s\n", debPdv(fdi, chxv));
+ }
+#endif
+
+ return wsrv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Edge lchw Newton itteration code */
+
+#ifdef NEVER /* Not actually used here */
+/* return weighted delta squared for target to edge at param value p */
+static double lchw_edge_sq(rspl *s, double *vt, double v[MXRI+1][MXRO+1], double p) {
+ int f, fdi = s->fdi;
+ double vv[MXRO]; /* Point at parameter location */
+ double dlsq; /* Delta L squared */
+ double da, db, dchsq; /* Delta CH squared */
+ double ct, cv, dc, dcsq; /* Delta C squared */
+ double lcomp, chcomp, ccomp;
+ double de;
+
+ /* Compute point at parameter location */
+ for (f = 0; f < fdi; f++)
+ vv[f] = (v[0][f] - v[1][f]) * p + v[1][f];
+
+ /* Delta L component */
+ dlsq = vv[0] - vt[0];
+ dlsq = dlsq * dlsq;
+ lcomp = s->rev.lchw_sq[0] * dlsq;
+
+ /* Delta CH component */
+ da = vv[1] - vt[1];
+ db = vv[2] - vt[2];
+ dchsq = da * da + db * db;
+ chcomp = s->rev.lchw_sq[2] * dchsq;
+
+ /* Compute chromanance for the two colors */
+ ct = sqrt(vt[1] * vt[1] + vt[2] * vt[2]);
+ cv = sqrt(vv[1] * vv[1] + vv[2] * vv[2]);
+ dc = ct - cv;
+ dcsq = dc * dc;
+
+ ccomp = s->rev.lchw_chsq * dcsq; /* w = cw - hw because dh = dch - dc */
+
+ de = lcomp + chcomp + ccomp;
+
+ return de;
+}
+#endif /* NEVER */
+
+/* return weighted 1st derivativ of delta squared for target to edge at param value p */
+static double lchw_edge_Dp_sq(rspl *s, double *vt, double v[MXRI+1][MXRO+1], double p) {
+ int f, fdi = s->fdi;
+ double vv[MXRO]; /* Point at parameter location */
+ double Dvv[MXRO]; /* Derivative wrt p of vv */
+ double dl, Ddlsq; /* Delta L squared */
+ double da, Ddasq, db, Ddbsq, Ddchsq; /* Delta CH squared */
+ double ct, cv, Dcv, dc, Ddc, Dvv1sq, Dvv2sq, Ddcsq; /* Delta C squared */
+ double Dlcomp, Dchcomp, Dccomp;
+ double Dde;
+
+ /* Compute point at parameter location */
+ for (f = 0; f < fdi; f++) {
+ vv[f] = (v[0][f] - v[1][f]) * p + v[1][f];
+ Dvv[f] = v[0][f] - v[1][f];
+ }
+
+ /* Delta L component */
+ dl = vv[0] - vt[0];
+ Ddlsq = 2.0 * dl * Dvv[0];
+ Dlcomp = s->rev.lchw_sq[0] * Ddlsq;
+
+ /* Delta CH component */
+ da = vv[1] - vt[1];
+ db = vv[2] - vt[2];
+ Ddasq = 2.0 * da * Dvv[1];
+ Ddbsq = 2.0 * db * Dvv[2];
+ Ddchsq = Ddasq + Ddbsq;
+ Dchcomp = s->rev.lchw_sq[2] * Ddchsq;
+
+ /* Compute chromanance for the two colors */
+ ct = sqrt(vt[1] * vt[1] + vt[2] * vt[2]);
+ cv = sqrt(vv[1] * vv[1] + vv[2] * vv[2]);
+ dc = cv - ct;
+ Dvv1sq = 2.0 * vv[1] * Dvv[1];
+ Dvv2sq = 2.0 * vv[2] * Dvv[2];
+ Dcv = 0.5/cv * (Dvv1sq + Dvv2sq);
+ Ddcsq = 2.0 * dc * Dcv;
+ Dccomp = s->rev.lchw_chsq * Ddcsq;
+
+ Dde = Dlcomp + Dchcomp + Dccomp;
+
+ return Dde;
+}
+
+/* return weighted 2nd derivative of delta squared for target to edge at param value p */
+static double lchw_edge_DDp_sq(rspl *s, double *vt, double v[MXRI+1][MXRO+1], double p) {
+ int f, fdi = s->fdi;
+ double vv[MXRO]; /* Point at parameter location */
+ double Dvv[MXRO]; /* Derivative wrt p of vv */
+ double DDvvsq[MXRO]; /* 2nd Derivative wrt p of vv */
+ double DDdchsq;
+ double ct, cv, Dcv, DDcv, dc, Dvv1sq, Dvv2sq, DDdcsq;
+ double DDlcomp, DDchcomp, DDccomp;
+ double DDde;
+
+ /* Compute point at parameter location */
+ for (f = 0; f < fdi; f++) {
+ vv[f] = (v[0][f] - v[1][f]) * p + v[1][f];
+ Dvv[f] = v[0][f] - v[1][f];
+ DDvvsq[f] = 2.0 * Dvv[f] * Dvv[f];
+ }
+
+ /* Delta L component */
+ DDlcomp = s->rev.lchw_sq[0] * DDvvsq[0];
+
+ /* Delta CH component */
+ DDdchsq = DDvvsq[1] + DDvvsq[2];
+ DDchcomp = s->rev.lchw_sq[2] * DDdchsq;
+
+ /* Compute chromanance for the two colors */
+ ct = sqrt(vt[1] * vt[1] + vt[2] * vt[2]);
+ cv = sqrt(vv[1] * vv[1] + vv[2] * vv[2]);
+ dc = cv - ct;
+ Dvv1sq = 2.0 * vv[1] * Dvv[1];
+ Dvv2sq = 2.0 * vv[2] * Dvv[2];
+
+ Dcv = 0.5/cv * (Dvv1sq + Dvv2sq);
+ DDcv = -0.5/(cv * cv) * Dcv * (Dvv1sq + Dvv2sq) + 0.5/cv * (DDvvsq[1] + DDvvsq[2]);
+
+ DDdcsq = 2.0 * (Dcv * Dcv + dc * DDcv);
+ DDccomp = s->rev.lchw_chsq * DDdcsq;
+
+ DDde = DDlcomp + DDchcomp + DDccomp;
+
+ return DDde;
+}
+
+/* Solve for an edge. Return nz of solution. */
+static int lchw_edge_solve(rspl *s, double *vv, double *p, double *vt, double v[MXRI+1][MXRO+1]) {
+ int i, f, fdi = s->fdi;
+ double pp, ee, dedp;
+ double e0, e1;
+
+ /* Decide whether there is a solution on this edge. */
+ /* This is reliable, and saves any itters in the loop. */
+ e0 = lchw_edge_Dp_sq(s, vt, v, 0.0);
+ e1 = lchw_edge_Dp_sq(s, vt, v, 1.0);
+
+ if ((e0 < 0.0 && e1 < 0.0)
+ || (e0 > 0.0 && e1 > 0.0)) {
+ return 0;
+ }
+
+ pp = 0.5;
+ for (i = 0; i < 30; i++) {
+ ee = lchw_edge_Dp_sq(s, vt, v, pp);
+ dedp = lchw_edge_DDp_sq(s, vt, v, pp);
+ pp -= ee/dedp;
+
+ if (fabs(ee) < 1e-6)
+ break;
+ }
+ ee = lchw_edge_Dp_sq(s, vt, v, pp);
+
+ if (fabs(ee) > 1e-6 || pp < -EPS || pp > (1.0 + EPS)) {
+ return 0;
+ }
+
+ /* Return solution (output space) */
+ for (f = 0; f < fdi; f++)
+ vv[f] = (v[0][f] - v[1][f]) * pp + v[1][f];
+
+ /* Return solution (simplex parameter space) */
+ *p = pp;
+
+ return 1;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Triangle lchw Newton itteration code */
+
+/* return weighted delta squared for target to triangle at param values p */
+/* [ 0 <= p0 <= p1 <= 1 ] */
+static double lchw_tri_sq(rspl *s, double *vt, double v[MXRI+1][MXRO+1], double *p) {
+ int f, fdi = s->fdi;
+ double vv[MXRO]; /* Point at parameter location */
+ double dlsq; /* Delta L squared */
+ double da, db, dchsq; /* Delta CH squared */
+ double ct, cv, dc, dcsq; /* Delta C squared */
+ double lcomp, chcomp, ccomp;
+ double de;
+
+ /* Compute point at parameter location */
+ for (f = 0; f < fdi; f++)
+ vv[f] = (v[0][f] - v[1][f]) * p[0]
+ + (v[1][f] - v[2][f]) * p[1]
+ + v[2][f];
+
+ /* Delta L component */
+ dlsq = vv[0] - vt[0];
+ dlsq = dlsq * dlsq;
+ lcomp = s->rev.lchw_sq[0] * dlsq;
+
+ /* Delta CH component */
+ da = vv[1] - vt[1];
+ db = vv[2] - vt[2];
+ dchsq = da * da + db * db;
+ chcomp = s->rev.lchw_sq[2] * dchsq;
+
+ /* Compute chromanance for the two colors */
+ ct = sqrt(vt[1] * vt[1] + vt[2] * vt[2]);
+ cv = sqrt(vv[1] * vv[1] + vv[2] * vv[2]);
+ dc = ct - cv;
+ dcsq = dc * dc;
+
+ ccomp = s->rev.lchw_chsq * dcsq; /* w = cw - hw because dh = dch - dc */
+
+ de = lcomp + chcomp + ccomp;
+
+ return de;
+}
+
+/* return weighted two 1st derivativ of delta squared for target to edge at param value p */
+static void lchw_tri_Dp_sq(rspl *s, double Dde[2], double *vt, double v[MXRI+1][MXRO+1], double *p) {
+ int f, fdi = s->fdi;
+ double vv[MXRO]; /* Point at parameter location */
+ double Dvv[2][MXRO]; /* Derivative wrt p of vv */
+ double dl, Ddl[2], Ddlsq[2]; /* Delta L squared */
+ double da, Ddasq[2], db, Ddbsq[2], Ddchsq[2]; /* Delta CH squared */
+ double ct, cv, Dcv[2], dc, Dvv1sq[2], Dvv2sq[2], Ddcsq[2]; /* Delta C squared */
+ double Dlcomp[2], Dchcomp[2], Dccomp[2];
+
+ /* Compute point at parameter location */
+ for (f = 0; f < fdi; f++) {
+ vv[f] = (v[0][f] - v[1][f]) * p[0]
+ + (v[1][f] - v[2][f]) * p[1]
+ + v[2][f];
+ Dvv[0][f] = v[0][f] - v[1][f];
+ Dvv[1][f] = v[1][f] - v[2][f];
+ }
+
+ /* Delta L component */
+ dl = vv[0] - vt[0];
+ Ddlsq[0] = 2.0 * dl * Dvv[0][0];
+ Ddlsq[1] = 2.0 * dl * Dvv[1][0];
+ Dlcomp[0] = s->rev.lchw_sq[0] * Ddlsq[0];
+ Dlcomp[1] = s->rev.lchw_sq[0] * Ddlsq[1];
+
+ /* Delta CH component */
+ da = vv[1] - vt[1];
+ db = vv[2] - vt[2];
+ Ddasq[0] = 2.0 * da * Dvv[0][1];
+ Ddasq[1] = 2.0 * da * Dvv[1][1];
+ Ddbsq[0] = 2.0 * db * Dvv[0][2];
+ Ddbsq[1] = 2.0 * db * Dvv[1][2];
+ Ddchsq[0] = Ddasq[0] + Ddbsq[0];
+ Ddchsq[1] = Ddasq[1] + Ddbsq[1];
+ Dchcomp[0] = s->rev.lchw_sq[2] * Ddchsq[0];
+ Dchcomp[1] = s->rev.lchw_sq[2] * Ddchsq[1];
+
+ /* Compute chromanance for the two colors */
+ ct = sqrt(vt[1] * vt[1] + vt[2] * vt[2]);
+ cv = sqrt(vv[1] * vv[1] + vv[2] * vv[2]);
+ dc = cv - ct;
+ Dvv1sq[0] = 2.0 * vv[1] * Dvv[0][1];
+ Dvv1sq[1] = 2.0 * vv[1] * Dvv[1][1];
+ Dvv2sq[0] = 2.0 * vv[2] * Dvv[0][2];
+ Dvv2sq[1] = 2.0 * vv[2] * Dvv[1][2];
+ Dcv[0] = 0.5/cv * (Dvv1sq[0] + Dvv2sq[0]);
+ Dcv[1] = 0.5/cv * (Dvv1sq[1] + Dvv2sq[1]);
+ Ddcsq[0] = 2.0 * dc * Dcv[0];
+ Ddcsq[1] = 2.0 * dc * Dcv[1];
+ Dccomp[0] = s->rev.lchw_chsq * Ddcsq[0];
+ Dccomp[1] = s->rev.lchw_chsq * Ddcsq[1];
+
+ Dde[0] = Dlcomp[0] + Dchcomp[0] + Dccomp[0];
+ Dde[1] = Dlcomp[1] + Dchcomp[1] + Dccomp[1];
+}
+
+/* return weighted four 2nd derivatives of delta squared for target to edge at param value p */
+/* ([first][second]) */
+static void lchw_tri_DDp_sq(rspl *s, double DDde[2][2], double *vt, double v[MXRI+1][MXRO+1], double *p) {
+ int f, fdi = s->fdi;
+ double vv[MXRO]; /* Point at parameter location */
+ double Dvv[2][MXRO]; /* Derivative wrt p of vv */
+ double DDvvsq[2][2][MXRO]; /* 2nd Derivative wrt p of vv */
+ double DDdchsq[2][2]; /* Delta CH squared */
+ double ct, cv, Dcv[2], DDcv[2][2], dc, Dvv1sq[2], Dvv2sq[2], DDdcsq[2][2];
+ double DDlcomp[2][2], DDchcomp[2][2], DDccomp[2][2];
+
+ /* Due to comutivity, [0][1] == [1][0], so we omit */
+ /* those redundant calculations. */
+
+ /* Compute point at parameter location */
+ for (f = 0; f < fdi; f++) {
+ vv[f] = (v[0][f] - v[1][f]) * p[0]
+ + (v[1][f] - v[2][f]) * p[1]
+ + v[2][f];
+ Dvv[0][f] = v[0][f] - v[1][f];
+ Dvv[1][f] = v[1][f] - v[2][f];
+
+ DDvvsq[0][0][f] = 2.0 * Dvv[0][f] * Dvv[0][f];
+ DDvvsq[1][0][f] = 2.0 * Dvv[1][f] * Dvv[0][f];
+// DDvvsq[0][1][f] = 2.0 * Dvv[0][f] * Dvv[1][f];
+ DDvvsq[1][1][f] = 2.0 * Dvv[1][f] * Dvv[1][f];
+ }
+
+ /* Delta L component */
+ DDlcomp[0][0] = s->rev.lchw_sq[0] * DDvvsq[0][0][0];
+ DDlcomp[1][0] = s->rev.lchw_sq[0] * DDvvsq[1][0][0];
+// DDlcomp[0][1] = s->rev.lchw_sq[0] * DDvvsq[0][1][0];
+ DDlcomp[1][1] = s->rev.lchw_sq[0] * DDvvsq[1][1][0];
+
+ /* Delta CH component */
+ DDdchsq[0][0] = DDvvsq[0][0][1] + DDvvsq[0][0][2];
+ DDdchsq[1][0] = DDvvsq[1][0][1] + DDvvsq[1][0][2];
+// DDdchsq[0][1] = DDvvsq[0][1][1] + DDvvsq[0][1][2];
+ DDdchsq[1][1] = DDvvsq[1][1][1] + DDvvsq[1][1][2];
+
+ DDchcomp[0][0] = s->rev.lchw_sq[2] * DDdchsq[0][0];
+ DDchcomp[1][0] = s->rev.lchw_sq[2] * DDdchsq[1][0];
+// DDchcomp[0][1] = s->rev.lchw_sq[2] * DDdchsq[0][1];
+ DDchcomp[1][1] = s->rev.lchw_sq[2] * DDdchsq[1][1];
+
+ /* Compute chromanance for the two colors */
+ ct = sqrt(vt[1] * vt[1] + vt[2] * vt[2]);
+ cv = sqrt(vv[1] * vv[1] + vv[2] * vv[2]);
+ dc = cv - ct;
+
+ Dvv1sq[0] = 2.0 * vv[1] * Dvv[0][1];
+ Dvv1sq[1] = 2.0 * vv[1] * Dvv[1][1];
+
+ Dvv2sq[0] = 2.0 * vv[2] * Dvv[0][2];
+ Dvv2sq[1] = 2.0 * vv[2] * Dvv[1][2];
+
+ Dcv[0] = 0.5/cv * (Dvv1sq[0] + Dvv2sq[0]);
+ Dcv[1] = 0.5/cv * (Dvv1sq[1] + Dvv2sq[1]);
+
+
+ DDcv[0][0] = -0.5/(cv * cv) * Dcv[0] * (Dvv1sq[0] + Dvv2sq[0])
+ + 0.5/cv * (DDvvsq[0][0][1] + DDvvsq[0][0][2]);
+
+ DDcv[1][0] = -0.5/(cv * cv) * Dcv[0] * (Dvv1sq[1] + Dvv2sq[1])
+ + 0.5/cv * (DDvvsq[1][0][1] + DDvvsq[1][0][2]);
+
+// DDcv[0][1] = -0.5/(cv * cv) * Dcv[1] * (Dvv1sq[0] + Dvv2sq[0])
+// + 0.5/cv * (DDvvsq[0][1][1] + DDvvsq[0][1][2]);
+
+ DDcv[1][1] = -0.5/(cv * cv) * Dcv[1] * (Dvv1sq[1] + Dvv2sq[1])
+ + 0.5/cv * (DDvvsq[1][1][1] + DDvvsq[1][1][2]);
+
+ DDdcsq[0][0] = 2.0 * (Dcv[0] * Dcv[0] + dc * DDcv[0][0]);
+ DDdcsq[1][0] = 2.0 * (Dcv[1] * Dcv[0] + dc * DDcv[1][0]);
+// DDdcsq[0][1] = 2.0 * (Dcv[0] * Dcv[1] + dc * DDcv[0][1]);
+ DDdcsq[1][1] = 2.0 * (Dcv[1] * Dcv[1] + dc * DDcv[1][1]);
+
+ DDccomp[0][0] = s->rev.lchw_chsq * DDdcsq[0][0];
+ DDccomp[1][0] = s->rev.lchw_chsq * DDdcsq[1][0];
+// DDccomp[0][1] = s->rev.lchw_chsq * DDdcsq[0][1];
+ DDccomp[1][1] = s->rev.lchw_chsq * DDdcsq[1][1];
+
+ DDde[0][0] = DDlcomp[0][0] + DDchcomp[0][0] + DDccomp[0][0];
+ DDde[1][0] = DDlcomp[1][0] + DDchcomp[1][0] + DDccomp[1][0];
+// DDde[0][1] = DDlcomp[0][1] + DDchcomp[0][1] + DDccomp[0][1];
+ DDde[0][1] = DDde[1][0];
+ DDde[1][1] = DDlcomp[1][1] + DDchcomp[1][1] + DDccomp[1][1];
+}
+
+
+/* Solve for a triangle face. Return nz of solution. */
+static int lchw_tri_solve(rspl *s, double *vv, double *p, double *vt, double v[MXRI+1][MXRO+1]) {
+ int f, fdi = s->fdi;
+ int i, j, k;
+ double pp[2], ee[2], dedp[2][2];
+ int ff1 = 0, ff2 = 0, fit = -1;
+
+ /* Decide whether there is a solution in this triangle */
+ j = k = 0;
+ pp[0] = 0.0; pp[1] = 0.0;
+ lchw_tri_Dp_sq(s, ee, vt, v, pp);
+ if (ee[0] < 0.0) j++;
+ if (ee[1] < 0.0) k++;
+
+ pp[0] = 0.0; pp[1] = 1.0;
+ lchw_tri_Dp_sq(s, ee, vt, v, pp);
+ if (ee[0] < 0.0) j++;
+ if (ee[1] < 0.0) k++;
+
+ if (j != 1 || k != 1) {
+ pp[0] = 1.0; pp[1] = 1.0;
+ lchw_tri_Dp_sq(s, ee, vt, v, pp);
+ if (ee[0] < 0.0) j++;
+ if (ee[1] < 0.0) k++;
+
+ /* Making this || filters out lots more for an avg itter of 0.74, */
+ /* but has a failure rate of 1 in 50000. */
+ /* This less stringent filter has an avg itter of 2.0 and 0 failure rate. */
+ if ((j == 0 || j == 3) && (k == 0 || k == 3)) {
+ return 0;
+ }
+ }
+
+ pp[0] = 0.3333; pp[1] = 0.6667;
+
+ for (i = 0; i < 30; i++) {
+ double det;
+
+ lchw_tri_Dp_sq(s, ee, vt, v, pp);
+ lchw_tri_DDp_sq(s, dedp, vt, v, pp);
+
+ /* Correct the point using inverse of dedp */
+ det = (dedp[0][0] * dedp[1][1] - dedp[0][1] * dedp[1][0]);
+ if (fabs(det) < 1e-20)
+ break; /* Hmm. */
+
+ det = 1.0/det;
+ pp[0] -= det * ( dedp[1][1] * ee[0] - dedp[0][1] * ee[1]);
+ pp[1] -= det * (-dedp[1][0] * ee[0] + dedp[0][0] * ee[1]);
+
+ /* If we're sufficiently close to zero point */
+ if (fabs(ee[0]) < 1e-6 && fabs(ee[1]) < 1e-6)
+ break;
+
+#ifdef NEVER
+#define THR 0.25
+ /* If we're too far out of bounds, give up */
+ /* (Speeds things up by about 40% at the cost of failing */
+ /* some that would suceed.) */
+ if (i >= 2 && (pp[0] < -THR || pp[0] > (1.0 + THR) || pp[1] < -THR || pp[1] > (1.0 + THR)
+ || pp[1] < (pp[0]-THR))) {
+ return 0;
+ }
+#undef THR
+#endif
+ }
+
+ lchw_tri_Dp_sq(s, ee, vt, v, pp);
+
+ if (fabs(ee[0]) > 1e-6 || fabs(ee[1]) > 1e-6
+ || pp[0] < -EPS || pp[1] < (pp[0]-EPS) || pp[1] > (1.0 + EPS)) {
+ return 0;
+ }
+
+ /* Return solution (output space) */
+ for (f = 0; f < fdi; f++) {
+ vv[f] = (v[0][f] - v[1][f]) * pp[0]
+ + (v[1][f] - v[2][f]) * pp[1]
+ + v[2][f];
+ }
+ /* Return solution (simplex parameter space) */
+ p[0] = pp[0];
+ p[1] = pp[1];
+
+ return 1;
+}
/* -------------------------------------------------------- */
/* Cell/simplex object lower level code */
@@ -3209,17 +4620,16 @@ rspl *s
/* Cell code */
-static void free_cell_contents(cell *c);
-static cell *cache_rcell(revcache *r, int ix, int force);
-static void uncache_rcell(revcache *r, cell *cp);
+static void free_cell_contents(fxcell *c);
+static fxcell *cache_fxcell(revcache *r, int ix, int force);
+static void uncache_fxcell(revcache *r, fxcell *cp);
-/* Return a pointer to an appropriate reverse cell */
-/* cache structure. None of the sub simplex lists will */
-/* be initialised. */
-/* NOTE: must unget_cell() (== uncache_rcell()) when cell */
+/* Return a pointer to an appropriate fxcell cache structure. */
+/* None of the sub simplex lists will be initialised. */
+/* NOTE: must unget_cell() (== uncache_fxcell()) when fxcell */
/* is no longer needed */
/* Return NULL if we ran out of room in the cache. */
-static cell *get_rcell(
+static fxcell *get_fxcell(
schbase *b, /* Base search information */
int ix, /* fwd index of cell */
int force /* if nz, force memory allocation, so that we have at least one cell */
@@ -3228,9 +4638,9 @@ int force /* if nz, force memory allocation, so that we have at least one cell
int ee, e, di = s->di;
int p2di = (1<<di);
int ff, f, fdi = s->fdi;
- cell *c;
+ fxcell *c;
- c = cache_rcell(s->rev.cache, ix, force); /* Fetch it from the cache and lock it */
+ c = cache_fxcell(s->rev.cache, ix, force); /* Fetch it from the cache and lock it */
if (c == NULL)
return NULL;
@@ -3282,76 +4692,15 @@ int force /* if nz, force memory allocation, so that we have at least one cell
}
}
- /* Compute the output bounding sphere for fast rejection testing */
+ /* Compute the output bounding group for fast rejection testing */
{
- double *min[MXRO], *max[MXRO]; /* Pointers to points with min/max values */
- double radsq = -1.0; /* Span/radius squared */
- double rad;
- int spf = 0;
-
- /* Find verticies of cell that have min and max values in output space */
- for (f = 0; f < fdi; f++)
- min[f] = max[f] = NULL;
+ double *vp[POW2MXRI];
- for (ee = 0; ee < p2di; ee++) {
- double *vp = c->v[ee];
- for (f = 0; f < fdi; f++) {
- if (min[f] == NULL || min[f][f] > vp[f])
- min[f] = vp;
- if (max[f] == NULL || max[f][f] < vp[f])
- max[f] = vp;
- }
- }
-
- /* Find the pair of points with the largest span (diameter) in output space */
- for (ff = 0; ff < fdi; ff++) {
- double ss;
- for (ss = 0.0, f = 0; f < fdi; f++) {
- double tt;
- tt = max[ff][f] - min[ff][f];
- ss += tt * tt;
- }
- if (ss > radsq) {
- radsq = ss;
- spf = ff; /* Output dimension max was in */
- }
- }
+ /* Make array of pointers to double vectors */
+ for (ee = 0; ee < p2di; ee++)
+ vp[ee] = c->v[ee];
- /* Set initial bounding sphere */
- for (f = 0; f < fdi; f++) {
- c->bcent[f] = (max[spf][f] + min[spf][f])/2.0;
- }
- radsq /= 4.0; /* diam^2 -> rad^2 */
- c->bradsq = radsq;
- rad = c->brad = sqrt(radsq);
-
- /* Go though all the points again, expanding sphere if necessary */
- for (ee = 0; ee < p2di; ee++) {
- double ss;
- double *vp = c->v[ee];
-
- /* Compute distance squared of point to bounding shere */
- for (ss = 0.0, f = 0; f < fdi; f++) {
- double tt = vp[f] - c->bcent[f];
- ss += tt * tt;
- }
- if (ss > radsq) {
- double tt;
- /* DBG(("Expanding bounding sphere by %f\n",sqrt(ss) - rad)); */
-
- ss = sqrt(ss) + EPS; /* Radius to point */
- rad = (rad + ss)/2.0;
- c->bradsq = radsq = rad * rad;
- tt = ss - rad;
- for (f = 0; f < fdi; f++) {
- c->bcent[f] = (rad * c->bcent[f] + tt * vp[f])/ss;
- }
-
- } else {
- /* DBG(("Bounding sphere encloses by %f\n",rad - sqrt(ss))); */
- }
- }
- c->bradsq += EPS;
+ nn_grpinit(s, &c->g, vp, p2di, NULL);
}
c->flags = CELL_FLAG_1;
}
@@ -3359,7 +4708,7 @@ int force /* if nz, force memory allocation, so that we have at least one cell
return c;
}
-void free_simplex_info(cell *c, int dof);
+void free_simplex_info(fxcell *c, int dof);
/* Free up any allocated simplexes in a cell, */
/* and set the pointers to NULL. */
@@ -3367,7 +4716,7 @@ void free_simplex_info(cell *c, int dof);
/* the cache index or unthrheaded from the mru list). */
static void
free_cell_contents(
-cell *c
+fxcell *c
) {
int nsdi;
@@ -3392,7 +4741,6 @@ int primes[] = {
853,
1489,
3373,
- 3373,
6863,
12919,
23333,
@@ -3400,6 +4748,9 @@ int primes[] = {
97849,
146221,
254941,
+ 407843,
+ 756869,
+ 999983,
-1
};
@@ -3419,7 +4770,7 @@ unsigned int simplex_hash(revcache *rc, int sdi, int efdi, int *vix) {
/* Allocate and do the basic initialisation for a DOF list of simplexes */
void alloc_simplexes(
-cell *c,
+fxcell *c,
int nsdi /* Non limited sub simplex dimensionality */
) {
rspl *s = c->s;
@@ -3497,7 +4848,7 @@ int nsdi /* Non limited sub simplex dimensionality */
//if ((max - min) > EPS) printf("~1 Found simplex sdi %d, efdi %d, min = %f, max = %f, limitv = %f\n", sdi, efdi, min,max,s->limitv);
if (isclip) { /* Limit clipped simplex */
/* (Make sure it straddles the limit boundary) */
- if (max < s->limitv || min > s->limitv)
+ if (max <= s->limitv || min > s->limitv)
continue; /* Discard this simplex - it can't straddle the ink limit */
//printf("~1 using sub simplex sdi %d, efdi %d, min = %f, max = %f, limitv = %f\n", sdi, efdi, min,max,s->limitv);
} else {
@@ -3514,7 +4865,7 @@ int nsdi /* Non limited sub simplex dimensionality */
/* Allocate space for all the DOF simplexes that will be used */
if (so > 0) {
if ((c->sx[nsdi] = (simplex **) rev_calloc(s, so, sizeof(simplex *))) == NULL)
- error("rspl malloc failed - reverse cell simplexes - list of pointers");
+ error("rspl malloc failed - fxcell simplexes - list of pointers");
INCSZ(s, so * sizeof(simplex *));
}
@@ -3552,7 +4903,7 @@ int nsdi /* Non limited sub simplex dimensionality */
x = c->sx[nsdi][so];
- /* If this is a shared simplex, see if we already have it in another cell */
+ /* If this is a shared face simplex, see if we already have it in another fxcell */
if (x == NULL && psxi->face) {
unsigned int hash;
//printf("~1 looking for existing simplex nsdi = %d\n",nsdi);
@@ -3576,7 +4927,7 @@ int nsdi /* Non limited sub simplex dimensionality */
/* Doesn't already exist */
if (x == NULL) {
if ((x = (simplex *) rev_calloc(s, 1, sizeof(simplex))) == NULL)
- error("rspl malloc failed - reverse cell simplexes - base simplex %d bytes",sizeof(simplex));
+ error("rspl malloc failed - fxcell simplexes - base simplex %d bytes",sizeof(simplex));
INCSZ(s, sizeof(simplex));
x->refcount = 1;
x->touch = s->rev.stouch-1;
@@ -3638,7 +4989,7 @@ int nsdi /* Non limited sub simplex dimensionality */
x->aloc2 = x->aloc5 = NULL; /* Matrix allocations not done yet */
- /* Add it to the face shared simplex hash index */
+ /* Add it to the shared face simplex hash index */
if (x->psxi->face) {
unsigned int hash;
int i;
@@ -3701,7 +5052,7 @@ int nsdi /* Non limited sub simplex dimensionality */
/* Free up any allocated for a list of sub-simplexes */
void
free_simplex_info(
-cell *c,
+fxcell *c,
int nsdi /* non limit sub simplex dimensionaity */
) {
int si, sxno = c->sxno[nsdi]; /* Number of simplexes */
@@ -3792,7 +5143,6 @@ simplex *x, /* Simplex */
double *p /* Input coords in simplex space */
) {
rspl *s = x->s;
- schbase *b = s->rev.sb;
int fdi = s->fdi;
int e, sdi = x->sdi; /* simplex dimensionality */
double cp, lp;
@@ -3839,6 +5189,61 @@ double *p /* Input coords in simplex space */
return rv;
}
+/* Check that an input space vector of a simplex meets the ink limit. */
+/* Return zero if outside the simplex, */
+/* 1 normally if within the simplex, */
+/* and 2 if it would be over the ink limit if limit was enabled. */
+/* This is the same as within_simplex() but only checks the ink limit. */
+static int
+within_simplex_limit(
+simplex *x, /* Simplex */
+double *p /* Input coords in simplex space */
+) {
+ rspl *s = x->s;
+ int fdi = s->fdi;
+ int e, sdi = x->sdi; /* simplex dimensionality */
+ int rv = 1;
+
+ /* Compute limit using interp. - assume simplex would have been trivially rejected */
+ if (s->limitf != NULL) {
+ double sum = 0.0; /* Might be over the limit */
+ for (e = 0; e < sdi; e++)
+ sum += p[e] * (x->v[e][fdi] - x->v[e+1][fdi]);
+ sum += x->v[sdi][fdi];
+ if (sum > s->limitv) {
+ if (s->limiten != 0)
+ return 0; /* Exceeds ink limit */
+ else
+ rv = 2; /* would have exceeded limit */
+ }
+ }
+ return rv;
+}
+
+/* Similar check to within_simplex(), but with explicit simplex definition */
+/* and no ink limit check. Returns 0 if outside, 1 if within */
+static int
+simple_within_simplex(
+double v[MXRI+1][MXRO], /* Vertex values */
+double *p, /* Input coords in simplex space */
+int sdi /* input dimensionality of simplex */
+) {
+ int e;
+ double cp, lp;
+
+ /* Check we are within baricentric limits */
+ for (lp = 0.0, e = 0; e < sdi; e++) {
+ cp = p[e];
+ if ((cp+EPS) < lp) /* Outside baricentric or not in correct */
+ return 0; /* order for this simplex */
+ lp = cp;
+ }
+ if ((1.0+EPS) < lp) /* outside baricentric range */
+ return 0;
+
+ return 1;
+}
+
/* Convert vector from simplex space to absolute cartesian space */
static void simplex_to_abs(
simplex *x,
@@ -3868,23 +5273,29 @@ double *in /* Input in simplex space */
/* with CLIPSX sub-simplexes. */
/* Note that no line equation values are returned if fdi = 1, */
/* since there is no such thing as an implicit line equation. */
+/* (Re-usable version for lines in general) */
static void
-init_line_eq(
-schbase *b,
+init_line_eq_imp(
+rspl *s,
+schbase *b, /* to set cdir, may be NULL if not needed. */
+double ***pcla, /* pointer to clip vector LHS implicit equation matrix */
+double clb[MXRO+1], /* Clip vector RHS implicit equation vector */
double st[MXRO], /* Start point */
-double de[MXRO] /* Delta */
+double de[MXRO], /* Delta */
+int inkeq /* nz to add ink limit target equation if s->limitf != NULL */
) {
- rspl *s = b->s;
int ff, f, fdi = s->fdi;
int i, p;
double lgst;
+ double **cla = *pcla;
DBG(("Computing clipping line implicit equation, dim = %d\n", fdi));
/* Pick a pivot element */
for (lgst = -1.0, p = -1, f = 0; f < fdi; f++) {
double tt = de[f];
- b->cdir[f] = tt; /* Stash this away */
+ if (b != NULL)
+ b->cdir[f] = tt; /* Stash this away */
tt = fabs(tt);
if (tt > lgst) {
lgst = tt;
@@ -3894,8 +5305,10 @@ double de[MXRO] /* Delta */
if (p < 0) /* Shouldn't happen */
error("rspl rev, internal, trying to cope with zero length clip line\n");
- if (b->cla == NULL)
- b->cla = dmatrix(0, fdi-1, 0, fdi); /* Allow for ink limit supliment */
+ if (cla == NULL) {
+ cla = dmatrix(0, fdi-1, 0, fdi); /* Allow for ink limit supliment */
+ *pcla = cla;
+ }
for (i = ff = 0; ff < fdi; ff++) { /* For the input rows */
if (ff == p) {
@@ -3903,28 +5316,28 @@ double de[MXRO] /* Delta */
}
for (f = 0; f < fdi; f++) { /* For input & output columns */
if (f == p) {
- b->cla[i][f] = -de[ff]; /* Last column is -ve delta value */
+ cla[i][f] = -de[ff]; /* Last column is -ve delta value */
} else if (f == ff) {
- b->cla[i][f] = de[p]; /* Diagonal is pivot value */
+ cla[i][f] = de[p]; /* Diagonal is pivot value */
} else {
- b->cla[i][f] = 0.0; /* Else zero */
+ cla[i][f] = 0.0; /* Else zero */
}
}
- b->clb[i] = de[p] * st[ff] - de[ff] * st[p];
+ clb[i] = de[p] * st[ff] - de[ff] * st[p];
i++;
}
/* Add ink limit target equation - */
/* interpolated ink value == target */
- if (s->limitf != NULL) {
+ if (inkeq && s->limitf != NULL) {
for (i = 0; i < (fdi-1); i++)
- b->cla[i][fdi] = 0.0;
+ cla[i][fdi] = 0.0;
for (f = 0; f < fdi; f++)
- b->cla[fdi-1][f] = 0.0;
+ cla[fdi-1][f] = 0.0;
- b->cla[fdi-1][fdi] = 1.0;
- b->clb[fdi-1] = s->limitv;
+ cla[fdi-1][fdi] = 1.0;
+ clb[fdi-1] = s->limitv;
}
#ifdef NEVER
@@ -3941,9 +5354,9 @@ double de[MXRO] /* Delta */
for (ff = 0; ff < (fdi-1); ff++) {
v[ff] = 0.0;
for (f = 0; f < fdi; f++) {
- v[ff] += b->cla[ff][f] * pnt[f];
+ v[ff] += cla[ff][f] * pnt[f];
}
- v[ff] -= b->clb[ff];
+ v[ff] -= clb[ff];
if (v[ff] < 0.0)
v[ff] = -v[ff];
if (v[ff] > 0.000001) {
@@ -3957,6 +5370,18 @@ double de[MXRO] /* Delta */
}
+/* Version of above used to set vector clipping line up */
+static void
+init_line_eq(
+schbase *b,
+double st[MXRO], /* Start point */
+double de[MXRO] /* Delta */
+) {
+ DBG(("Computing clipping line implicit equation, dim = %d\n", b->s->fdi));
+
+ init_line_eq_imp(b->s, b, &b->cla, b->clb, st, de, 1);
+}
+
/* - - - - - - */
/* Simpex solution info #2 */
@@ -3985,7 +5410,7 @@ add_lu_svd(simplex *x) {
+ sizeof(int) * sdi;
if ((x->aloc2 = mem = (char *) rev_malloc(x->s, asize)) == NULL)
- error("rspl malloc failed - reverse cell sub-simplex matricies");
+ error("rspl malloc failed - fxcell sub-simplex matricies");
INCSZ(x->s, asize);
/* Allocate biggest to smallest (double, pointers, ints) */
@@ -4017,7 +5442,7 @@ add_lu_svd(simplex *x) {
+ sizeof(double *) * (efdi + 2 * sdi);
if ((x->aloc2 = mem = (char *) rev_malloc(x->s, asize)) == NULL)
- error("rspl malloc failed - reverse cell sub-simplex matricies");
+ error("rspl malloc failed - fxcell sub-simplex matricies");
INCSZ(x->s, asize);
/* Allocate biggest to smallest (double, pointers, ints) */
@@ -4232,7 +5657,7 @@ simplex *x
+ sizeof(int) * dof;
if ((x->aloc5 = mem = (char *) rev_malloc(x->s, asize)) == NULL)
- error("rspl malloc failed - reverse cell sub-simplex matricies");
+ error("rspl malloc failed - fxcell sub-simplex matricies");
INCSZ(x->s, asize);
/* Allocate biggest to smallest (double, pointers, ints) */
@@ -4261,7 +5686,7 @@ simplex *x
+ sizeof(double) * (dof * (naux + dof + 1));
if ((x->aloc5 = mem = (char *) rev_malloc(x->s, asize)) == NULL)
- error("rspl malloc failed - reverse cell sub-simplex matricies");
+ error("rspl malloc failed - fxcell sub-simplex matricies");
INCSZ(x->s, asize);
/* Allocate biggest to smallest (double, pointers, ints) */
@@ -4368,7 +5793,7 @@ int sdi /* Sub-simplex dimensionality (range 0 - di) */
xip->sdi = sdi;
xip->nospx = nospx;
if ((xip->spxi = (psxinfo *) rev_calloc(s, nospx, sizeof(psxinfo))) == NULL)
- error("rspl malloc failed - reverse cell sub-simplex info array");
+ error("rspl malloc failed - fxcell sub-simplex info array");
INCSZ(s, nospx * sizeof(psxinfo));
DBG(("Number of subsimplex = %d\n",nospx));
@@ -4487,7 +5912,7 @@ ssxinfo *xip /* Pointer to sub-simplex info structure */
/* ====================================================== */
/* Reverse cell cache code */
-/* Allocate and initialise the reverse cell cache */
+/* Allocate and initialise the fxcell cache */
static revcache *
alloc_revcache(
rspl *s
@@ -4496,7 +5921,7 @@ rspl *s
DBG(("alloc_revcache called\n"));
if ((rc = (revcache *) rev_calloc(s, 1, sizeof(revcache))) == NULL)
- error("rspl malloc failed - reverse cell cache");
+ error("rspl malloc failed - fxcell cache");
INCSZ(s, sizeof(revcache));
rc->s = s; /* For stats */
@@ -4504,9 +5929,9 @@ rspl *s
/* Allocate an initial cell hash index */
rc->cell_hash_size = primes[0];
- if ((rc->hashtop = (cell **) rev_calloc(s, rc->cell_hash_size, sizeof(cell *))) == NULL)
- error("rspl malloc failed - reverse cell cache index");
- INCSZ(s, rc->cell_hash_size * sizeof(cell *));
+ if ((rc->hashtop = (fxcell **) rev_calloc(s, rc->cell_hash_size, sizeof(fxcell *))) == NULL)
+ error("rspl malloc failed - fxcell cache index");
+ INCSZ(s, rc->cell_hash_size * sizeof(fxcell *));
/* Allocate an initial simplex face match hash index */
rc->spx_hash_size = primes[0];
@@ -4518,23 +5943,23 @@ rspl *s
return rc;
}
-/* Free the reverse cell cache */
+/* Free the fxcell cache */
static void
free_revcache(revcache *rc) {
int i;
- cell *cp, *ncp;
+ fxcell *cp, *ncp;
/* Free any stuff allocated in the cell contents, and the cell itself. */
for (cp = rc->mrubot; cp != NULL; cp = ncp) {
ncp = cp->mruup;
free_cell_contents(cp);
free(cp);
- DECSZ(rc->s, sizeof(cell));
+ DECSZ(rc->s, sizeof(fxcell));
}
/* Free the hash indexes */
free(rc->hashtop);
- DECSZ(rc->s, rc->cell_hash_size * sizeof(cell *));
+ DECSZ(rc->s, rc->cell_hash_size * sizeof(fxcell *));
free(rc->spxhashtop);
DECSZ(rc->s, rc->spx_hash_size * sizeof(simplex *));
@@ -4548,7 +5973,7 @@ invalidate_revcache(
revcache *rc)
{
int i;
- cell *cp;
+ fxcell *cp;
rc->nunlocked = 0;
@@ -4574,23 +5999,23 @@ revcache *rc)
/* This may re-size the hash index too. */
/* Return the pointer to the new cell. */
/* (Note it's not our job here to honour the memory limit) */
-static cell *
+static fxcell *
increase_revcache(
revcache *rc
) {
- cell *nxcell; /* Newly allocated cell */
+ fxcell *nxcell; /* Newly allocated fxcell */
int i;
- DBG(("Adding another chunk of cells to cache\n"));
+// DBG(("Adding another cell to cache\n"));
#ifdef NEVER /* We may be called with force != 0 */
if (rc->s->rev.sz >= rc->s->rev.max_sz)
return NULL;
#endif
- if ((nxcell = (cell *) rev_calloc(rc->s, 1, sizeof(cell))) == NULL)
- error("rspl malloc failed - reverse cache cells");
- INCSZ(rc->s, sizeof(cell));
+ if ((nxcell = (fxcell *) rev_calloc(rc->s, 1, sizeof(fxcell))) == NULL)
+ error("rspl malloc failed - reverse fxcells");
+ INCSZ(rc->s, sizeof(fxcell));
nxcell->s = rc->s;
@@ -4605,7 +6030,7 @@ revcache *rc
rc->nacells++;
rc->nunlocked++;
- DBG(("cache is now %d cells\n",rc->nacells));
+// DBG(("cache is now %d cells\n",rc->nacells));
/* See if the hash index should be re-sized */
if (rc->nacells > (HASH_FILL_RATIO * rc->cell_hash_size)) {
@@ -4613,19 +6038,19 @@ revcache *rc
;
if (primes[i] > 0) {
int cell_hash_size = rc->cell_hash_size; /* Old */
- cell **hashtop = rc->hashtop;
+ fxcell **hashtop = rc->hashtop;
rc->cell_hash_size = primes[i];
DBG(("Increasing cell cache hash index to %d\n",cell_hash_size));
/* Allocate a new index */
- if ((rc->hashtop = (cell **) rev_calloc(rc->s, rc->cell_hash_size, sizeof(cell *))) == NULL)
- error("rspl malloc failed - reverse cell cache index");
- INCSZ(rc->s, rc->cell_hash_size * sizeof(cell *));
+ if ((rc->hashtop = (fxcell **) rev_calloc(rc->s, rc->cell_hash_size, sizeof(fxcell *))) == NULL)
+ error("rspl malloc failed - fxcell cache index");
+ INCSZ(rc->s, rc->cell_hash_size * sizeof(fxcell *));
/* Transfer all the cells to the new index */
for (i = 0; i < cell_hash_size; i++) {
- cell *c, *nc;
+ fxcell *c, *nc;
for (c = hashtop[i]; c != NULL; c = nc) {
int hash;
nc = c->hlink;
@@ -4637,7 +6062,7 @@ revcache *rc
/* Done with old index */
free(hashtop);
- DECSZ(rc->s, cell_hash_size * sizeof(cell *));
+ DECSZ(rc->s, cell_hash_size * sizeof(fxcell *));
}
}
@@ -4651,11 +6076,11 @@ revcache *rc /* Reverse cache structure */
) {
int hit = 0;
int hash;
- cell *cp;
+ fxcell *cp;
DBG(("Decreasing cell cache memory allocation by freeing a cell\n"));
- /* Use the least recently used unlocked cell */
+ /* Use the least recently used unlocked fxcell */
for (cp = rc->mrubot; cp != NULL && cp->refcount > 0; cp = cp->mruup)
;
@@ -4674,7 +6099,7 @@ revcache *rc /* Reverse cache structure */
if (rc->hashtop[hash] == cp) {
rc->hashtop[hash] = cp->hlink;
} else {
- cell *c;
+ fxcell *c;
for (c = rc->hashtop[hash]; c != NULL && c->hlink != cp; c = c->hlink)
;
if (c != NULL)
@@ -4692,30 +6117,30 @@ revcache *rc /* Reverse cache structure */
cp->mrudown->mruup = cp->mruup;
cp->mruup = cp->mrudown = NULL;
free(cp);
- DECSZ(rc->s, sizeof(cell));
+ DECSZ(rc->s, sizeof(fxcell));
rc->nacells--;
rc->nunlocked--;
- DBG(("Freed a rev cache cell\n"));
+ DBG(("Freed a rev fxcell\n"));
return 1;
}
-/* Return a pointer to an appropriate reverse cell */
-/* cache structure. cell->flags will be 0 if the cell */
+/* Return a pointer to an appropriate fxcell */
+/* cache structure. cell->flags will be 0 if the fxcell */
/* has been reallocated. cell contents will be 0 if */
/* never used before. */
/* The cell reference count is incremented, so that it */
/* can't be thrown out of the cache. The cell must be */
-/* released with uncache_rcell() when it's no longer needed. */
+/* released with uncache_fxcell() when it's no longer needed. */
/* return NULL if we ran out of room in the cache */
-static cell *cache_rcell(
+static fxcell *cache_fxcell(
revcache *rc, /* Reverse cache structure */
int ix, /* fwd index of cell */
-int force /* if nz, force memory allocation, so that we have at least one cell */
+int force /* if nz, force memory allocation, so that we have at least one fxcell */
) {
int hit = 0;
int hash;
- cell *cp;
+ fxcell *cp;
/* keep memory in check - fail if we're out of memory and can't free any */
/* (Doesn't matter if it might be a hit, it will get picked up the next time) */
@@ -4744,12 +6169,13 @@ int force /* if nz, force memory allocation, so that we have at least one cell
break;
}
}
- if (!hit) { /* No hit, use new cell or the least recently used cell */
+ if (!hit) { /* No hit, use new cell or the least recently used fxcell */
int ohash;
/* If we haven't used all our memory, or if we are forced and have */
- /* no cell we can re-use, then noallocate another cell */
- if (rc->s->rev.sz < rc->s->rev.max_sz || (force && rc->nunlocked == 0)) {
+ /* no cell we can re-use, then allocate another fxcell */
+ if (rc->s->rev.sz < rc->s->rev.max_sz
+ || (force && rc->nunlocked == 0)) {
cp = increase_revcache(rc);
hash = HASH(rc,ix); /* Re-compute hash in case hash size changed */
//printf("~1 using new cell\n");
@@ -4757,7 +6183,7 @@ int force /* if nz, force memory allocation, so that we have at least one cell
//printf("~1 memory limit has been reached, using old cell\n");
for (;;) {
- /* Use the least recently used unlocked cell */
+ /* Use the least recently used unlocked fxcell */
for (cp = rc->mrubot; cp != NULL && cp->refcount > 0; cp = cp->mruup)
;
@@ -4775,14 +6201,14 @@ int force /* if nz, force memory allocation, so that we have at least one cell
if (rc->hashtop[ohash] == cp) {
rc->hashtop[ohash] = cp->hlink;
} else {
- cell *c;
+ fxcell *c;
for (c = rc->hashtop[ohash]; c != NULL && c->hlink != cp; c = c->hlink)
;
if (c != NULL)
c->hlink = cp->hlink;
}
- /* If we're now under the memory limit, use this cell */
+ /* If we're now under the memory limit, use this fxcell */
if (rc->s->rev.sz < rc->s->rev.max_sz) {
break;
}
@@ -4800,7 +6226,7 @@ int force /* if nz, force memory allocation, so that we have at least one cell
cp->mrudown->mruup = cp->mruup;
cp->mruup = cp->mrudown = NULL;
free(cp);
- DECSZ(rc->s, sizeof(cell));
+ DECSZ(rc->s, sizeof(fxcell));
rc->nacells--;
rc->nunlocked--;
}
@@ -4843,9 +6269,9 @@ int force /* if nz, force memory allocation, so that we have at least one cell
/* Tell the cache that we aren't using this cell anymore, */
/* but to keep it in case it is needed again. */
-static void uncache_rcell(
+static void uncache_fxcell(
revcache *rc, /* Reverse cache structure */
-cell *cp
+fxcell *cp
) {
if (cp->refcount > 0) {
cp->refcount--;
@@ -4859,8 +6285,14 @@ cell *cp
/* ====================================================== */
/* Reverse rspl setup functions */
+static void del_bxcell(rspl *s, bxcell *bx);
+static void free_sharelist(rspl *s);
+static void free_indexlist(rspl *s, int **rp);
+static void free_surfhash(rspl *s, int del);
+static void free_surflist(rspl *s);
+
/* Called by rspl initialisation */
-/* Note that reverse cell lookup tables are not */
+/* Note that fxcell lookup tables are not */
/* allocated & created until the first call */
/* to a reverse interpolation function. */
void
@@ -4885,6 +6317,7 @@ init_rev(rspl *s) {
/* Methods */
s->rev_set_limit = rev_set_limit_rspl;
s->rev_get_limit = rev_get_limit_rspl;
+ s->rev_set_lchw = rev_set_lchw;
s->rev_interp = rev_interp_rspl;
s->rev_locus = rev_locus_rspl;
s->rev_locus_segs = rev_locus_segs_rspl;
@@ -4947,13 +6380,15 @@ rspl *s /* Pointer to rspl grid */
/* Free up the Second section */
if (s->rev.nnrev != NULL) {
- /* Free arrays at grid points, taking care of reference count */
+
+ /* Free up nn list sharelist records - this will free and set */
+ /* any shared lists to NULL */
+ free_sharelist(s);
+
+ /* Free any remaining arrays at grid points */
for (rpp = s->rev.nnrev; rpp < (s->rev.nnrev + s->rev.no); rpp++) {
- if ((rp = *rpp) != NULL && --rp[2] <= 0) {
- DECSZ(s, rp[0] * sizeof(int));
- free(*rpp);
- *rpp = NULL;
- }
+ if (*rpp != NULL)
+ free_indexlist(s, rpp);
}
free(s->rev.nnrev);
DECSZ(s, s->rev.no * sizeof(int *));
@@ -4992,13 +6427,10 @@ rspl *s /* Pointer to rspl grid */
s->rev.rev_valid = 0;
if (s->rev.rev != NULL) {
- /* Free arrays at grid points, taking care of reference count */
+ /* Free arrays at grid points */
for (rpp = s->rev.rev; rpp < (s->rev.rev + s->rev.no); rpp++) {
- if ((rp = *rpp) != NULL && --rp[2] <= 0) {
- DECSZ(s, rp[0] * sizeof(int));
- free(*rpp);
- *rpp = NULL;
- }
+ if (*rpp != NULL)
+ free_indexlist(s, rpp);
}
free(s->rev.rev);
DECSZ(s, s->rev.no * sizeof(int *));
@@ -5016,111 +6448,2334 @@ rspl *s /* Pointer to rspl grid */
s->rev.no = 0;
s->rev.inited = 0;
}
+
+ /* Free up surface linked list and the bxcells in it. */
+ free_surflist(s);
+
+ /* Free up surface bxcell hash index */
+ free_surfhash(s, 0);
+
DBG(("rev allocation left after free = %d bytes\n",s->rev.sz));
+
+#ifdef CHECK_NNLU
+ print_nnck(s);
+#endif /* CHECK_NNLU */
}
+
+/* ========================================================== */
+/* reverse lookup acceleration structure initialisation code. */
+
+/* The reverse lookup relies on a search of the fwd interpolation tables.
+ To eliminate out of gamut points quickly, to provide a starting point for
+ the search, and to guarantee that all possible reverse solutions are discovered,
+ a spatial indexing structure is used to provide a list of starting candidate
+ forward cell indexes for a given output value. (rev.rev[])
+ The reverse structure contains two fdi dimensional bwd cell grids, each element of the
+ cell grid holding the indexes of the forward interpolation grid.
+ The rev[] grid holds fwd cell indexes which intersect that bwd cell's range of
+ output values. A rev[] cell will be empty if there is no potential exact solution.
+ The nnrev[] grid holds fwd cell indexes of those cells that may be the lch weighted
+ closest to that bwd cell.
+ The rev.nnrev[] array is almost a complement of the rev.rev[] array,
+ with the exception of any overlap near the gamut surface.
+ Since many of the nnrev[] bwd cells map to nearly the same surface region, many
+ of the fwd cell lists are shared.
+
+ When s->rev.fastsetup is set, then the rev.nnrev[] grid is left empty, and
+ any call for nn lookup is satisfied by filling the requisite rev.nnrev[] on-demand,
+ by an exaustive search of the surface bwd cells (rev.surflist)
+
+ Note that unlike the forward grid which is composed of verticies,
+ these rev lists are composed of fwd cells.
+
+ The nnrev[] setup code identifies possible surface bwd revp[] cells
+ by them being face neighbors of empty (out of gamut) bwd cells.
+ It then converts the vertexes of the fwd cell list into a vertex list,
+ and "thins" the list by deleting any vertex that is shaded by a triangle
+ that other vertexes are part of. This is done on a backward cell basis,
+ but includes vertexes of other possibly shadowed backward cells.
+
+ If ink limiting is being used, then over ink limit partners to
+ the vertexes are added in, and then the list of vertexes is
+ converted back into fwd cells in a way that ensures 2 dimensional
+ connectivity of the cells, while minimizing the number of
+ extra (non surface) vertexes implied by the fwd cells.
+
+ */
+
+/*
+ The gamut hull fwcell finding code is not robust - it assumes visiblity
+ of the surface from some center point(s).
+
+ Perfect gamut hull finding approach would be something like this:
+ (using vertex and triangle caching structures.)
+
+ Add all triangles on device gamut surface with at least
+ one vertex within ink limit.
+
+ Add all triangles that are part of a full di simplex
+ with at least one vertex within ink limit (and not on device gamut),
+ where all the other verticies of the simplex are on one
+ side of the triangle (non-monotonic surfaces).
+
+ Add all triangles on the ink limit plane.
+ (Will be 1 or more triangles per simplex that has
+ 1..di verticies that are over the ink limit.)
+
+ Check all triangles for instersection with each other.
+ Convert any such intersections into smaller, non-intersecting
+ triangles that share verticies along intersection line.
+
+ Delete triangles that have dangling edges (i.e. triangles that
+ have edges with odd number of associated triangles).
+ This is to eliminate "dangling" triangles. Should only be left
+ with "bubles" in surface after this ?
+
+ Bubbles join at edges where more than 2 triangles co-incide.
+ Can internal bubles be "un-stitched" if we can decide which
+ triangles are part of a bubble ????
+ i.e. use even/odd inside rule for points between
+ the triangles at the edge.
+
+ Delete all vertexes and associated triangles that are
+ inside the surface.
+ Will odd/even test work ? - i.e. from vertex of triangle,
+ is on surface if intersections in one direction are even, and
+ other direction are odd.
+
+ Or "point within odd number of tetrahedrons formed with point on surface" ?
+ - seems to be the same as the odd/even rule. Can't detect connectivity.
+
+ Or do this using a winding number algorithm
+ with signed crossings optimization ?
+ <Point in Polyhedron Testing Using Spherical Polygons, Graphics Gems V pp42>
+ But do we have to order triangles in a consistent direction ?
+ How to do this when more than 2 triangles meet at an adge ???
+ i.e. catch-22 - need to know which are inside triangles to
+ set edge direction, but need edge direction to detect inside-outside.
+
+*/
+
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#if defined(REVTABLESTATS) || defined(DEBUG)
+static int bxcount = 0;
+static int maxbxcount = 0;
+#endif
+
+static void add2indexlist(rspl *s, int **rpp, int ix, int shrec);
+static void comp_shadow_group(rspl *s, double *gcent, double *rgc, double *pcc,
+ double *pdw, double *gc, double (*v)[MXRO], int nverta);
+
+/* Allocate a new bx cell. */
+/* (Doesn't add to hash or list) */
+static bxcell *new_bxcell(
+ rspl *s,
+ int ix, /* rev[] index of cell being created */
+ int *gc, /* Coord of rev[] cell being created */
+ bxcell *ss, /* search starting bxcell to commence with, this cell if NULL */
+ double sdist, /* Est. distance from this cell to six */
+ char *vflag /* If non-NULL, create a super-cell if far from seed */
+) {
+ int f, fdi = s->fdi;
+ int i;
+ bxcell *bx = NULL;
+ DCOUNT(cc, MXRO, fdi, 0, 0, 2); /* Vertex counter */
+
+//printf("~1 creating new bxcell with index %d\n",ix);
+ if ((bx = (bxcell *) rev_calloc(s, 1, sizeof(bxcell))) == NULL)
+ error("rspl malloc failed - rev bxcell structs");
+ INCSZ(s, sizeof(bxcell));
+
+ bx->ix = ix;
+ bx->tix = -1;
+ for (f = 0; f < fdi; f++)
+ bx->gc[f] = gc[f];
+ bx->ss = (ss == NULL) ? bx : ss;
+ bx->sdist = sdist;
+
+//printf("~1 new_bxcell ix %d, co %s, base %s\n",ix,debPiv(s->fdi, bx->gc),debPdv(s->fdi, vp[0]));
+
+ /* super-cell code (to speed filling) */
+ if (vflag != NULL && (vflag[ix] & 2) == 0 && ss != NULL) {
+ double codist = 0.0;
+
+ /* Compute distance of seed from this cell */
+ for (codist = 0.0, f = 0; f < fdi; f++) {
+ int tt = bx->gc[f] - ss->gc[f];
+ codist += tt * tt;
+ }
+ codist = sqrt(codist);
+
+//printf("~1 codist %f, codist/s->rev.res = %f\n",codist,codist/s->rev.res);
+ /* Create a super-cell if we are far enough from the seed. */
+ /* (this determines what portion of filling uses super-cells) */
+// if (codist >= 1.0 && (codist/s->rev.res) > 0.05)
+ if (codist >= 2.0)
+ {
+ int co[MXRO];
+ DCOUNT(ss, MXRO, s->fdi, -1, -1, 2);
+ double (*vp)[MXRO];
+ double **vpp;
+ int nverts;
+//printf("~1 creating super-cell for bx %d\n",ix);
+
+ /* Maximum number of verticies for all surrounders */
+ for (nverts = (1 << fdi), f = 0; f < fdi; f++)
+ nverts *= 3;
+
+ if ((vp = (double(*)[MXRO]) rev_calloc(s, nverts, sizeof(double) * MXRO)) == NULL)
+ error("rspl malloc failed - rev bxcell vertex list");
+ INCSZ(s, nverts * sizeof(double) * MXRO);
+
+ if ((vpp = (double **) rev_calloc(s, nverts, sizeof(double *))) == NULL)
+ error("rspl malloc failed - rev bxcell vertex list");
+ INCSZ(s, nverts * sizeof(double *));
+
+ /* Search around this cell for other cells to be filled */
+ i = 0;
+ DC_INIT(ss);
+ while (!DC_DONE(ss)) {
+ int nix = ix;
+ for (f = 0; f < fdi; f++) {
+ nix += ss[f] * s->rev.coi[f];
+ co[f] = bx->gc[f] + ss[f];
+ if (co[f] < 0 || co[f] >= s->rev.res)
+ break;
+ }
+
+ /* If within boundary and un-filled non-surface bxcell */
+ if (f >= fdi && (vflag[nix] & 0xf) == 0) {
+ add2indexlist(s, &bx->scell, nix, 0);
+ vflag[nix] = (vflag[nix] & ~0xf) | 1; /* Assume it's now on the seed list */
+
+ /* Create vertex locations for this bxcell */
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ for (f = 0; f < fdi; f++)
+ vp[i][f] = (co[f] + cc[f]) * s->rev.gw[f] + s->rev.gl[f];
+ vpp[i] = vp[i];
+ DC_INC(cc);
+ i++;
+ }
+ }
+ DC_INC(ss);
+ }
+
+ /* Init the group boundary data */
+ nn_grpinit(s, &bx->g, vpp, i, NULL);
+
+ /* Compute the default shadowing test width and distance */
+ /* (Not actually used for super-cell ?) */
+ comp_shadow_group(s, s->rev.ocent, NULL, &bx->cc, &bx->dw, bx->g.bcent, vp, i);
+
+ free(vpp);
+ DECSZ(s, nverts * sizeof(double *));
+
+ free(vp);
+ DECSZ(s, nverts * sizeof(double) * MXRO);
+//printf(" - %d sub-cells\n",bx->scell[1]-3);
+ }
+ }
+
+ if (bx->scell == NULL) {
+ double vp[POW2MXRO][MXRO];
+ double *vpp[POW2MXRO];
+
+ /* Create vertex locations for this bxcell */
+ i = 0;
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ for (f = 0; f < fdi; f++)
+ vp[i][f] = (gc[f] + cc[f]) * s->rev.gw[f] + s->rev.gl[f];
+ vpp[i] = vp[i];
+ DC_INC(cc);
+ i++;
+ }
+
+ /* Init the group boundary data */
+ nn_grpinit(s, &bx->g, vpp, i, NULL);
+
+ /* Compute the default shadowing test width and distance */
+ comp_shadow_group(s, s->rev.ocent, NULL, &bx->cc, &bx->dw, bx->g.bcent, vp, 1 << fdi);
+ }
-#ifdef NEVER /* Test code */
-/* Reverse closest find using exaustive pseudo hilbert search */
-static void debug_find_closest_rev(
+//printf("~1 grp bcent %s, brad %f\n",debPdv(s->fdi, bx->g.bcent), bx->g.brad);
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ bxcount++;
+ if (bxcount > maxbxcount)
+ maxbxcount = bxcount;
+//printf("~1 now %d bxcells\n",bxcount);
+#endif
+ return bx;
+}
+
+/* Free a bxcell (up to caller to free bx->sl, remove from cache etc.) */
+/* We free the super-cell info. */
+static void del_bxcell(rspl *s, bxcell *bx) {
+ if (bx->scell != NULL) /* If this is a supercell */
+ free_indexlist(s, &bx->scell);
+ if (bx->dl != NULL) /* We have a deleted fwd vertex list */
+ free_indexlist(s, &bx->dl);
+ free(bx);
+ DECSZ(s, sizeof(bxcell));
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ bxcount--;
+//printf("~1 now %d bxcells\n",--bxcount);
+#endif
+}
+
+/* Allocate the surflist hash index */
+static void create_surfhash(rspl *s) {
+
+ s->rev.surf_hash_size = primes[2]; /* 1489 */
+ if ((s->rev.surfhash = (bxcell **) rev_calloc(s, s->rev.surf_hash_size, sizeof(bxcell *))) == NULL)
+ error("rspl malloc failed - reverse bxcell surface cache index");
+ INCSZ(s, s->rev.surf_hash_size * sizeof(bxcell *));
+}
+
+/* Add a bxcell to the surface hash list */
+static void add_bxcell_hash(rspl *s, bxcell *bx) {
+ unsigned int hash = 0;
+
+ hash = bx->ix % s->rev.surf_hash_size;
+ bx->hlink = s->rev.surfhash[hash];
+ s->rev.surfhash[hash] = bx;
+}
+
+/* Remove a bxcell from the surface hash list. */
+/* Doesn't delete the bxcell though. */
+static void rem_bxcell_hash(rspl *s, int ix) {
+ unsigned int hash = 0;
+ bxcell *bx = NULL, **pbx;
+
+ hash = ix % s->rev.surf_hash_size;
+
+ for (pbx = &s->rev.surfhash[hash], bx = *pbx; bx != NULL; pbx = &bx->hlink, bx = *pbx) {
+ if (bx->ix == ix) {
+ *pbx = bx->hlink;
+ return;
+ }
+ }
+}
+
+/* Fetch a surface bxcell from the surface hash list, given its index, or */
+/* Return NULL if none */
+static bxcell *get_surface_bxcell(rspl *s, int ix) {
+ unsigned int hash = 0;
+ bxcell *bx = NULL;
+
+ hash = ix % s->rev.surf_hash_size;
+
+ for (bx = s->rev.surfhash[hash]; bx != NULL; bx = bx->hlink) {
+ if (bx->ix == ix)
+ return bx;
+ }
+ return NULL;
+}
+
+/* Free up surface linked list and delete the bxcells. */
+/* (If we use this, don't use free_surfhash with del set.) */
+static void free_surflist(rspl *s) {
+
+ while (s->rev.surflist != NULL) {
+ bxcell *this = s->rev.surflist;
+ s->rev.surflist = s->rev.surflist->slist;
+ if (this->sl != NULL)
+ free_indexlist(s, &this->sl);
+ del_bxcell(s, this);
+ }
+}
+
+
+/* If del is set, free up all the bxcell cells in the hash index, */
+/* then free the surfhash itself. */
+/* (Use instead of surflist to manage allocation, */
+/* or to clean up hashlist after surflist has been freed.) */
+static void free_surfhash(rspl *s, int del) {
+
+ if (s->rev.surfhash != NULL) {
+ if (del) {
+ int i;
+ for (i = 0; i < s->rev.surf_hash_size; i++) {
+ bxcell *bx, *nbx;
+ for (bx = s->rev.surfhash[i]; bx != NULL; bx = nbx) {
+ nbx = bx->hlink;
+ if (bx->sl != NULL)
+ free_indexlist(s, &bx->sl);
+ del_bxcell(s, bx);
+ }
+ }
+ }
+ free(s->rev.surfhash);
+ DECSZ(s, s->rev.surf_hash_size * sizeof(bxcell *));
+ s->rev.surfhash = NULL;
+ s->rev.surf_hash_size = 0;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Structure to cache prime vertex information when filtering surface */
+/* cell vertex lists. */
+
+/* vertex status */
+typedef enum {
+ vtx_norm = 0, /* Normal vertex in primary bxcell */
+ vtx_sha = 1, /* Vertex has been shadowed */
+ vtx_del = 2, /* Vertex has been deleted because it's shadowed */
+ vtx_oil = 3 /* Vertex is over ink limit */
+} vstat;
+
+struct _vtxrec {
+ int ix; /* fwd index of vertex */
+ int cix; /* Cell index for this vertex */
+ double v[MXRO]; /* Output value of vertex */
+ double dist; /* Distance from center point squared */
+ int tcount; /* Touch count for converting to fwd cells */
+ int acount; /* Actual count for converting to fwd cells */
+
+ vstat status;
+ int tix; /* Target vertex when being created */
+
+ struct _vtxrec *hlink; /* Linked list of vtxrecs with same ix hash */
+ int rix; /* nnrev[] index vertex falls into */
+ int ival[MXRO]; /* nnrev[] coordinate rix */
+
+ char prim; /* nz when primary vertex of bx (not shadow bx) */
+ char cross; /* nz when part of suspected crossed triangle */
+ char pres; /* nz when preserved shadowed vertex from crossed triangle */
+
+ char tflag; /* nz when on tlist */
+ struct _vtxrec *tlist; /* Linked list of vertexes for nnrev[] cell/freelist */
+
+#ifdef REVVRML
+ int addvtx; /* Vertex that caused a bxcell to be added */
+ int vrmlix; /* Index for plotting */
+#endif
+
+}; typedef struct _vtxrec vtxrec;
+
+struct _vtxcache {
+ vtxrec *vtxlist; /* vertex list for soring/itterating selected nnrev cell. */
+ int nilist; /* Number of vertexes in the list */
+
+ int hash_size; /* Current size of vtxrec hash list */
+ vtxrec **hash; /* hash index list */
+
+ vtxrec *freelist; /* Unused vertex structures (to avoid memory allocs) */
+}; typedef struct _vtxcache vtxcache;
+
+
+/* Create the vertex list & hash */
+static void create_vtxrec_list(rspl *s, vtxcache *vc) {
+ vc->hash_size = primes[3]; /* 3373 */
+ if ((vc->hash = (vtxrec **) rev_calloc(s, vc->hash_size, sizeof(vtxrec *))) == NULL)
+ error("rspl malloc failed - vtxrec cache index");
+ INCSZ(s, vc->hash_size * sizeof(vtxrec *));
+ vc->vtxlist = NULL;
+ vc->nilist = 0;
+ vc->freelist = NULL;
+}
+
+/* Clear the vertex hash and list */
+static void clear_vtxrec_lists(rspl *s, vtxcache *vc) {
+ vtxrec *vp, *nvp;
+ int i;
+
+ /* Transfer all records in hash to freelist, */
+ /* and clear hash. */
+ for (i = 0; i < vc->hash_size; i++) {
+ for (vp = vc->hash[i]; vp != NULL; vp = nvp) {
+ nvp = vp->hlink;
+ vp->tlist = vc->freelist;
+ vc->freelist = vp;
+ }
+ vc->hash[i] = NULL;
+ }
+
+ vc->vtxlist = NULL;
+ vc->nilist = 0;
+}
+
+/* Free the vertex list & hash */
+static void free_vtxrec_list(rspl *s, vtxcache *vc) {
+ clear_vtxrec_lists(s, vc);
+
+ while (vc->freelist != NULL) {
+ vtxrec *this = vc->freelist;
+ vc->freelist = vc->freelist->tlist;
+ free(this);
+ DECSZ(s, sizeof(vtxrec));
+ }
+ free(vc->hash);
+ DECSZ(s, vc->hash_size * sizeof(vtxrec *));
+ vc->hash = NULL;
+ vc->hash_size = 0;
+}
+
+/* Add a vtxrec to the vertex hash list */
+static void add_vtxrec_hash(vtxcache *vc, vtxrec *vx) {
+ unsigned int hash = 0;
+
+ hash = vx->ix % vc->hash_size;
+ vx->hlink = vc->hash[hash];
+ vc->hash[hash] = vx;
+}
+
+/* Delete a vtxrec from the vertex hash list */
+/* (Assume it's not part of vtxlist!) */
+static void del_vtxrec_hash(vtxcache *vc, int ix) {
+ unsigned int hash = 0;
+ vtxrec *vx = NULL, **pvx;
+
+ hash = ix % vc->hash_size;
+
+ for (pvx = &vc->hash[hash], vx = *pvx; vx != NULL; pvx = &vx->hlink, vx = *pvx) {
+ if (vx->ix == ix) {
+ *pvx = vx->hlink;
+ vx->tlist = vc->freelist;
+ vc->freelist = vx;
+ vx->hlink = NULL;
+ return;
+ }
+ }
+}
+
+/* Fetch a surface vtxrec from the hash list, given its index */
+/* Return NULL if none */
+static vtxrec *get_vtxrec(vtxcache *vc, int ix) {
+ unsigned int hash = 0;
+ vtxrec *vx = NULL;
+
+ hash = ix % vc->hash_size;
+
+ for (vx = vc->hash[hash]; vx != NULL; vx = vx->hlink) {
+ if (vx->ix == ix)
+ return vx;
+ }
+ return NULL;
+}
+
+/* Create a new vtxrec or return the current one. */
+/* Allocates it, adds it to cache. */
+/* DOESN"T add it to vtxlist. */
+static vtxrec *new_vtxrec(
+ rspl *s,
+ vtxcache *vc,
+ int ix /* fwd index of vertex */
+) {
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+ vtxrec *vx = NULL;
+ float *gp;
+ int rix;
+ int rgres_1 = s->rev.res -1; /* rgres -1 == maximum base coord value */
+
+ /* See if we've already got this vertex */
+ if ((vx = get_vtxrec(vc, ix)) != NULL)
+ return vx;
+
+ /* Fetch or allocate a new structure */
+ if (vc->freelist != NULL) { /* Grab one from free list */
+ vx = vc->freelist;
+ vc->freelist = vx->tlist;
+ memset((void *)vx, 0, sizeof(vtxrec));
+
+ } else {
+ if ((vx = (vtxrec *) rev_calloc(s, 1, sizeof(vtxrec))) == NULL)
+ error("rspl malloc failed - rev vtxrec structs");
+ INCSZ(s, sizeof(vtxrec));
+ }
+
+ /* Our fwd index */
+ vx->ix = ix;
+
+ /* Add it to the hash */
+ add_vtxrec_hash(vc, vx);
+
+ /* Fwd vertex array address */
+ gp = s->g.a + ix * s->g.pss;
+
+ /* Set cell index so that cell verticies don't exceed grid boundary */
+ vx->cix = ix;
+ for (e = 0; e < di; e++) {
+ if (G_FL(gp, e) == 0) /* At the top edge */
+ vx->cix -= s->g.ci[e]; /* Move cell base down a row */
+ }
+
+ /* Get the output value */
+ for (f = 0; f < fdi; f++)
+ vx->v[f] = gp[f];
+
+ /* Compute distance to overall center point squared */
+ vx->dist = 0.0;
+ for (f = 0; f < fdi; f++) {
+ double tt = gp[f] - s->rev.ocent[f];
+ vx->dist += tt * tt;
+ }
+
+ /* Figure the actual nncell it lands in */
+ for (rix = f = 0; f < fdi; f++) {
+ double t;
+ int mi;
+ double gw = s->rev.gw[f];
+ double gl = s->rev.gl[f];
+ t = (vx->v[f] - gl)/gw;
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi > rgres_1)
+ mi = rgres_1;
+ vx->ival[f] = mi;
+ rix += mi * s->rev.coi[f];
+ }
+ vx->rix = rix;
+
+ return vx;
+}
+
+/* Add a vertex to the list. */
+/* Don't add if already on list (if tflag set), or if shadowed) */
+/* set prim flag to value */
+static void add_vtxrec_list(vtxcache *vc, vtxrec *vx, int prim) {
+
+ vx->prim = (char)prim; /* Always set prim flag */
+
+ if (vx->tflag || vx->status != vtx_norm)
+ return;
+
+ vx->tlist = vc->vtxlist;
+ vc->vtxlist = vx;
+ vx->tflag = 1;
+ vc->nilist++;
+
+}
+
+int dumpvtxsort = 0;
+
+/* Sort the vertex linked list by dist. */
+/* Also reset the tflag */
+static void sort_vtxrec_list(rspl *s, vtxcache *vc) {
+ int i;
+ vtxrec **sort, *vx;
+
+ /* Create temporary array of pointers to vtxrec's in list */
+ if ((sort = (vtxrec **) rev_calloc(s, vc->nilist, sizeof(vtxrec *))) == NULL)
+ error("rspl malloc failed - rev vtxrec sort array");
+ INCSZ(s, vc->nilist * sizeof(vtxrec *));
+
+ for (i = 0, vx = vc->vtxlist; vx != NULL; vx = vx->tlist, i++)
+ sort[i] = vx;
+
+ /* Sort the list into ascending distance from center */
+#define HEAP_COMPARE(A,B) (A->dist < B->dist)
+ HEAPSORT(vtxrec *, sort, vc->nilist)
+#undef HEAP_COMPARE
+
+ /* Re-create the linked list in descending order */
+ vc->vtxlist = NULL;
+ for (i = 0; i < vc->nilist; i++) {
+ vx = sort[i];
+ vx->tlist = vc->vtxlist;
+ vc->vtxlist = vx;
+ vx->tflag = 0;
+ }
+
+ free(sort);
+ DECSZ(s, vc->nilist * sizeof(vtxrec *));
+
+#ifndef NEVER
+ if (dumpvtxsort) {
+ printf("sorted vertex list:\n");
+ for (i = 0, vx = vc->vtxlist; vx != NULL; vx = vx->tlist, i++)
+ printf("%d: ix %d, dist %f\n",i,vx->ix, sqrt(vx->dist));
+ }
+#endif
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Structure to cache surface triangle vertexes, to avoid repeated */
+/* shadowing test */
+
+struct _trirec{
+ int ix[3]; /* vertex indexes of triangle in simplex order */
+ struct _trirec *hlink; /* Linked list of triangles in hash/freelist */
+}; typedef struct _trirec trirec;
+
+typedef struct {
+ int hash_size; /* Current size of trirec hash list */
+ trirec **hash; /* hash index list */
+ trirec *freelist; /* Unused trirec structures (to avoid memory allocs) */
+} tricache;
+
+/* Create the tricache list & hash. */
+/* Set sm flag if we only want a small cache size */
+static void create_trirec(rspl *s, tricache *tc, int sm) {
+ if (sm)
+ tc->hash_size = primes[1]; /* 853 */
+ else
+ tc->hash_size = primes[5]; /* 12919 */
+ if ((tc->hash = (trirec **) rev_calloc(s, tc->hash_size, sizeof(trirec *))) == NULL)
+ error("rspl malloc failed - trirec cache index");
+ INCSZ(s, tc->hash_size * sizeof(trirec *));
+ tc->freelist = NULL;
+}
+
+/* Clear the trirec list & hash */
+static void clear_trirec(rspl *s, tricache *tc) {
+ int i;
+ trirec *tp, *ntp;
+
+ /* Transfer all records in hash to freelist, */
+ /* and clear hash. */
+ for (i = 0; i < tc->hash_size; i++) {
+ for (tp = tc->hash[i]; tp != NULL; tp = ntp) {
+ ntp = tp->hlink;
+ tp->hlink = tc->freelist;
+ tc->freelist = tp;
+ }
+ tc->hash[i] = NULL;
+ }
+}
+
+/* Free the triangle list & hash */
+static void free_trirec(rspl *s, tricache *tc) {
+ clear_trirec(s, tc);
+
+ while (tc->freelist != NULL) {
+ trirec *this = tc->freelist;
+ tc->freelist = tc->freelist->hlink;
+ free(this);
+ DECSZ(s, sizeof(trirec));
+ }
+ free(tc->hash);
+ DECSZ(s, tc->hash_size * sizeof(trirec *));
+ tc->hash = NULL;
+ tc->hash_size = 0;
+}
+
+/* Check if a triangle is in the cache. */
+/* return nz if it is, and z if it isn't, and add it. */
+static int check_trirec(rspl *s, tricache *tc, int *ix) {
+ int i;
+ unsigned int hash = 0;
+ trirec *tp = NULL;
+
+ hash = ix[0];
+ hash = hash * 17 + ix[1];
+ hash = hash * 17 + ix[2];
+ hash %= tc->hash_size;
+
+ for (tp = tc->hash[hash]; tp != NULL; tp = tp->hlink) {
+ if (tp->ix[0] == ix[0]
+ && tp->ix[1] == ix[1]
+ && tp->ix[2] == ix[2]) {
+//printf("check_trirec %d %d %d is in cache\n",ix[0], ix[1], ix[2]);
+ return 1;
+ }
+ }
+//printf("check_trirec %d %d %d NOT in cache\n",ix[0], ix[1], ix[2]);
+
+ /* Allocate a new structure */
+ if (tc->freelist != NULL) { /* Grab one from free list */
+ tp = tc->freelist;
+ tc->freelist = tp->hlink;
+ memset((void *)tp, 0, sizeof(trirec));
+
+ } else {
+ if ((tp = (trirec *) rev_calloc(s, 1, sizeof(trirec))) == NULL)
+ error("rspl malloc failed - rev trirec structs");
+ INCSZ(s, sizeof(trirec));
+ }
+
+ tp->ix[0] = ix[0];
+ tp->ix[1] = ix[1];
+ tp->ix[2] = ix[2];
+
+ /* add it into the hash */
+ tp->hlink = tc->hash[hash];
+ tc->hash[hash] = tp;
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Add another entry to an index/share list, taking care of any re-sizing */
+/* Set shlist if this is a sharer record */
+static void add2indexlist(rspl *s, int **rpp, int ix, int shrec) {
+ int *rp = *rpp;
+
+ if (rp == NULL) {
+ if ((rp = (int *) rev_malloc(s, 6 * sizeof(int))) == NULL)
+ error("rspl malloc failed - rev.grid list");
+ INCSZ(s, 6 * sizeof(int));
+ rp[0] = 6; /* Allocation */
+ rp[1] = 4; /* Next free Cell */
+ rp[2] = -1; /* share list index - default none */
+ rp[3] = ix; /* Index added to list */
+ rp[4] = -1; /* End of list marker */
+ *rpp = rp; /* Update pointer */
+ } else {
+ int z = rp[1], ll = rp[0];
+ if (z >= (ll-1)) { /* Not enough space */
+ if (!shrec && rp[2] != -1)
+ error("Re-allocating shared fwd index list");
+ INCSZ(s, ll * sizeof(int));
+ ll *= 2;
+ if ((rp = (int *) rev_realloc(s, rp, sizeof(int) * ll)) == NULL)
+ error("rspl realloc failed - rev.grid list size %d",ll);
+ rp[0] = ll; /* Allocation */
+ *rpp = rp; /* Update pointer */
+ }
+ rp[z++] = ix; /* Index added to list */
+ rp[z] = -1; /* End of list marker */
+ rp[1] = z; /* Next free Cell */
+ }
+}
+
+/* Copy an index list (i.e. from nnrev[] to bxcell->sl) */
+static void copy_indexlist(rspl *s, int **dp, int *sp) {
+ if (sp == NULL)
+ *dp = NULL;
+ else {
+ int i;
+ if ((*dp = (int *) rev_malloc(s, sp[0] * sizeof(int))) == NULL)
+ error("rspl malloc failed - rev.grid list");
+ INCSZ(s, sp[0] * sizeof(int));
+ for (i = 0; i <= sp[1]; i++)
+ (*dp)[i] = sp[i];
+ (*dp)[2] = -1;
+ }
+}
+
+/* Free an index list, at set it to NULL */
+static void free_indexlist(rspl *s, int **rp) {
+ if (*rp != NULL) {
+ DECSZ(s, (*rp)[0] * sizeof(int));
+ free(*rp);
+ *rp = NULL;
+ }
+}
+
+/* Add a (fwd index list) sharer to share list. */
+/* Record will be created if list[2] == -1, */
+/* or incremented otherwise. */
+/* sharerix is the index of the cell sharing the *list */
+static void add2sharelist(rspl *s, int sharerix, int *list) {
+ int *sharerec = NULL;
+
+ /* Create a new record and add our (one) sharer to it */
+ if (list[2] == -1) {
+ if (s->rev.sharellen >= s->rev.sharelaloc) {
+ /* Allocate another sharelist entry */
+ INCSZ(s, (10 + s->rev.sharelaloc) * sizeof(int *));
+ s->rev.sharelaloc = 10 + 2 * s->rev.sharelaloc;
+ if ((s->rev.sharelist = (int **)rev_realloc(s, s->rev.sharelist,
+ s->rev.sharelaloc * sizeof(int *))) == NULL)
+ error("add2sharelist: realloc failed");
+ }
+ add2indexlist(s, &sharerec, sharerix, 1);
+ s->rev.sharelist[s->rev.sharellen] = sharerec;
+ list[2] = s->rev.sharellen;
+ s->rev.sharellen++;
+
+ /* Add the sharer to the existing sharer list */
+ } else {
+ if (list[2] >= s->rev.sharellen)
+ error("add2sharelist got list with sharelist index out of range");
+ sharerec = s->rev.sharelist[list[2]];
+ add2indexlist(s, &sharerec, sharerix, 1);
+ s->rev.sharelist[list[2]] = sharerec;
+ }
+}
+
+/* Return the sharer list for the given (fwd cell) list */
+/* Return NULL if not shared */
+static int *getsharelist(rspl *s, int *list) {
+ if (list[2] == -1)
+ return NULL;
+ if (list[2] >= s->rev.sharellen) {
+ error("getsharelist got list with sharelist index out of range (%d > %d)",list[2],s->rev.sharellen);
+ }
+ return s->rev.sharelist[list[2]];
+}
+
+/* Free all the sharelist and the shared nnrev[] fwd cell lists as well */
+static void free_sharelist(rspl *s) {
+ if (s->rev.sharelist != NULL) {
+ int i, j;
+ for (i = 0; i < s->rev.sharellen; i++) {
+ int *shrec = s->rev.sharelist[i];
+
+ /* Free the shared fwd cell list */
+ if (shrec[1] > 3) {
+ int *clist = s->rev.nnrev[shrec[3]];
+ DECSZ(s, clist[0] * sizeof (int));
+ free(clist);
+ }
+
+ /* Make sure freeing of s->rev.nnrev[] doesn't free them twice */
+ for (j = 3; shrec[j] != -1; j++)
+ s->rev.nnrev[shrec[j]] = NULL;
+
+ DECSZ(s, s->rev.sharelist[i][0] * sizeof (int));
+ free(s->rev.sharelist[i]);
+ }
+ DECSZ(s, s->rev.sharelaloc * sizeof(int *));
+ free(s->rev.sharelist);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* For shadow bxcell testing, compute the delta distance */
+/* rev.ocent, and delta "width" between two vertex values. */
+
+/* Compute shadow testing group values */
+static void comp_shadow_group(
+ rspl *s,
+ double *gcent, /* In gamut center point to compute from */
+ double *rgc, /* Return group center if non-NULL */
+ double *pcc, /* Return distance of group center to gamut center */
+ double *pdw, /* Return width of furthest point from group center */
+ double *gc, /* if not-NULL, the group center */
+ double (*v)[MXRO], /* Input verticies */
+ int nvert /* Number of verticies */
+) {
+ double _gc[MXRO];
+ int i;
+ int f, fdi = s->fdi;
+ double cc; /* gamut center to group center */
+ double dw = -1.0; /* Largest goup vertex width */
+
+ /* if no group center given, compute one simply as an average */
+ /* (Used for triangle) */
+ if (gc == NULL) {
+ gc = _gc;
+ for (f = 0; f < fdi; f++)
+ gc[f] = 0.0;
+ for (i = 0; i < nvert; i++) {
+ for (f = 0; f < fdi; f++) {
+ gc[f] += v[i][f];
+ }
+ }
+ for (f = 0; f < fdi; f++)
+ gc[f] /= (double)nvert;
+ }
+
+ /* Return it if requested */
+ if (rgc != NULL) {
+ for (f = 0; f < fdi; f++)
+ rgc[f] = gc[f];
+ }
+
+ /* Compute distance from gamut center to group center */
+ for (cc = 0.0, f = 0; f < fdi; f++) {
+ double tt = gcent[f] - gc[f];
+ cc += tt * tt;
+ }
+ cc = sqrt(cc);
+
+ if (pcc != NULL)
+ *pcc = cc;
+
+ /* Compute width for each vertex, and track maximum */
+ for (i = 0; i < nvert; i++) {
+ double vlen, scale;
+ double sv[MXRO]; /* Vertex scaled to same distance as group center */
+ double w;
+
+ /* vertex length from gamut center */
+ for (vlen= 0.0, f = 0; f < fdi; f++) {
+ double tt = v[i][f] - gcent[f];
+ vlen += tt * tt;
+ }
+ vlen = sqrt(vlen);
+
+ if (vlen > 1e-6)
+ scale = cc/vlen;
+ else
+ scale = 1.0;
+
+ for (f = 0; f < fdi; f++)
+ sv[f] = (scale * (v[i][f] - gcent[f])) + gcent[f];
+
+ /* Distance from scaled vertex to group center */
+ for (w = 0.0, f = 0; f < fdi; f++) {
+ double tt = sv[f] - gc[f];
+ w += tt * tt;
+ }
+ if (w > dw)
+ dw = w;
+
+ }
+ dw = sqrt(dw);
+
+ if (pdw != NULL)
+ *pdw = dw;
+}
+
+/* Expand a bxcell's shadow testing group values based on it's vertex list */
+static void extend_bxcell_shadow_group(
+ rspl *s,
+ vtxcache *vc,
+ bxcell *bx
+) {
+ int *ip;
+ int f, fdi = s->fdi;
+ double dw;
+
+ if (bx->sl == NULL)
+ return;
+
+ /* Current dw squared */
+ dw = bx->dw * bx->dw;
+
+ /* Compute width for each vertex, and track maximum */
+ for (ip = bx->sl+3; *ip != -1; ip++) {
+ vtxrec *vx;
+ double vlen, scale;
+ double sv[MXRO]; /* Vertex scaled to same distance as group center */
+ double w;
+
+ if ((vx = get_vtxrec(vc, *ip)) == NULL)
+ continue;
+
+ /* vertex length from gamut center */
+ for (vlen= 0.0, f = 0; f < fdi; f++) {
+ double tt = vx->v[f] - s->rev.ocent[f];
+ vlen += tt * tt;
+ }
+ vlen = sqrt(vlen);
+
+ if (vlen > 1e-6)
+ scale = bx->cc/vlen;
+ else
+ scale = 1.0;
+
+ for (f = 0; f < fdi; f++)
+ sv[f] = (scale * (vx->v[f] - s->rev.ocent[f])) + s->rev.ocent[f];
+
+ /* Distance from scaled vertex to group center */
+ for (w = 0.0, f = 0; f < fdi; f++) {
+ double tt = sv[f] - bx->g.bcent[f];
+ w += tt * tt;
+ }
+ if (w > dw)
+ dw = w;
+
+ }
+ if (dw > bx->dw)
+ bx->dw = sqrt(dw);
+}
+
+/* Shadow group to group compare. Return nz if within range */
+static int shadow_group_group(
+ rspl *s,
+ double *gcent, /* Input gamut center point to compute from */
+ double *gc1, /* Reference group center point */
+ double cc1, /* Reference point cc value */
+ double dw1, /* Reference point dw value */
+ double *gc2, /* Comparison group center point */
+ double cc2, /* Comparison point cc value */
+ double dw2 /* Comparison point dw value */
+) {
+ int i;
+ int f, fdi = s->fdi;
+ double dot, scale;
+ double sv[MXRO]; /* Comparison group center scaled to same distance as ref center */
+ double w;
+
+ /* Compute dot product of cc1 and cc2 */
+ for (dot = 0.0, f = 0; f < fdi ; f++)
+ dot += (gc1[f] - gcent[f]) * (gc2[f] - gcent[f]);
+
+ /* If the groupls are not in the same direction, return false */
+ if (dot < 0.0)
+ return 0;
+
+ if (cc2 > 1e-6)
+ scale = cc1/cc2;
+ else
+ scale = 1.0;
+
+ for (f = 0; f < fdi; f++)
+ sv[f] = (scale * (gc2[f] - gcent[f])) + gcent[f];
+
+ /* Distance from scaled group center to ref. group center */
+ for (w = 0.0, f = 0; f < fdi; f++) {
+ double tt = sv[f] - gc1[f];
+ w += tt * tt;
+ }
+ w = sqrt(w);
+
+ if (w <= (dw1 + (scale * dw2) + EPS))
+ return 1;
+
+ return 0;
+}
+
+/* Shadow group to vertex compare. Return nz if within range */
+static int shadow_group_vertex(
+ rspl *s,
+ double *gcent, /* Input gamut center point to compute from */
+ double *gc1, /* Reference group center point */
+ double cc1, /* Reference point cc value */
+ double dw1, /* Reference point dw value */
+ double *v /* Comparison vertex location */
+) {
+ int i;
+ int f, fdi = s->fdi;
+ double vlen, dot, scale;
+ double sv[MXRO]; /* Vertex scaled to same distance as group center */
+ double w;
+
+ /* Compute dot product of cc1 and cc2 */
+ for (dot = 0.0, f = 0; f < fdi ; f++)
+
+ /* vertex length from center */
+ /* and dot product with group center vector */
+ for (vlen= 0.0, f = 0; f < fdi; f++) {
+ double tt = v[f] - gcent[f];
+ vlen += tt * tt;
+ dot += (gc1[f] - gcent[f]) * tt;
+ }
+
+ /* If the groupls are not in the same direction, return false */
+ if (dot < 0.0)
+ return 0;
+
+ vlen = sqrt(vlen);
+
+ if (vlen > 1e-6)
+ scale = cc1/vlen;
+ else
+ scale = 1.0;
+
+ for (f = 0; f < fdi; f++)
+ sv[f] = (scale * (v[f] - gcent[f])) + gcent[f];
+
+ /* Distance from scaled vertex to group center */
+ for (w = 0.0, f = 0; f < fdi; f++) {
+ double tt = sv[f] - gc1[f];
+ w += tt * tt;
+ }
+ w = sqrt(w);
+
+ if (w <= (dw1 + EPS))
+ return 1;
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Given a pointer to a bxcell, use the ->tlist to fill in the corresponding nnrev[]. */
+/* Expand and share lists with nearby nnrev[] cells if they are similar. */
+static void create_nnrev_list(
rspl *s,
-double *out,
-double *in
+bxcell *tx, /* Target nnrev[] cell */
+bxcell *ss, /* Head of solution list of surface nnrev[] cells */
+double emax /* smallest emax in solution list */
) {
- double best = 1e38;
- int e, f;
- rpsh counter; /* Pseudo-hilbert counter */
- int gc[MXDI]; /* Grid index value */
- double iv[MXDI];
- float *gp; /* Pointer to grid data */
+ int i, j;
+ bxcell *bx;
+ int *dp = NULL, *sp;
+ double *eminlist;
+ unsigned int hashk;
- rpsh_init(&counter, s->di, (unsigned int *)s->g.res, gc); /* Initialise counter */
- for (;;) {
- double dist;
+ DBG(("create_nnrev_list: di %d target cell ix %d co[] %s emax = %f\n",s->di, tx->ix,debPiv(s->fdi, tx->gc),emax));
- /* Compute grid pointer and input sample values */
- gp = s->g.a; /* Base of grid data */
- for (e = 0; e < s->di; e++) { /* Input tables */
- gp += s->g.fci[e] * gc[e]; /* Grid value pointer */
- iv[e] = s->g.l[e] + gc[e] * s->g.w[e]; /* Input sample values */
+ /* Update tx->ss and tx->sdist with best in tlist for future */
+ /* searches from this surface cell. */
+ tx->sdist = 1e200;
+ for (bx = ss; bx != NULL; bx = bx->tlist) {
+//printf("~1 checking ix %d\n",bx->ix);
+ if (bx->sdist < tx->emin) {
+ tx->ss = bx;
+ tx->sdist = bx->emin;
+ DBG((" Set target ss to ix %d, emin %f\n",tx->ss->ix, tx->sdist));
+//printf(" Set target ss to ix %d, emin %f\n",tx->ss->ix, tx->sdist);
}
+ }
+//printf("~1 set sdist\n");
- dist = 0.0;
- for (f = 0; f < s->fdi; f++) {
- double tt = in[f] - (double)gp[f];
- dist += tt * tt;
+#ifdef DEBUG2
+ {
+ int tot = 0;
+ printf(" Initial fwd list from following surface cells:\n");
+ for (bx = ss; bx != NULL; bx = bx->tlist) {
+ if (bx->emin <= emax) {
+ if (bx->sl == NULL)
+ error("rev create_nnrev_list: found empty surface bxcell");
+ printf(" ix %d co %s fwd count %d\n",bx->ix,debPiv(s->fdi, bx->gc),bx->sl[1]-3);
+ tot += bx->sl[1]-3;
+ }
}
- if (dist < best) {
- best = dist;
- for (e = 0; e < s->di; e++)
- out[e] = iv[e];
+ printf(" Total fwd cells = %d\n",tot);
+ }
+#endif
+
+ /* Create an initial list of fwd cells from all bxcells */
+ /* on the solution list that have ->emin <= emax */
+ for (bx = ss; bx != NULL; bx = bx->tlist) {
+//printf("~1 checking solution cell ix %d co %s\n",bx->ix,debPiv(s->fdi, bx->gc));
+ if (bx->emin <= emax) {
+//printf("~1 solution cell has emin %f < emax %f\n",bx->emin, emax);
+ sp = bx->sl;
+ if (sp == NULL)
+ error("rev create_nnrev_list: found empty surface bxcell %d",ss->ix);
+ for (sp += 3; *sp != -1; sp++)
+ add2indexlist(s, &dp, *sp, 0);
}
+ }
+
+ if (dp == NULL)
+ error("create_nnrev_list got NULL new list\n");
+
+#ifdef DEBUG2
+ printf(" Initial fwd list (length %d, alloc %d):\n",dp[1]-3,dp[0]);
+ for (i = 3; dp[i] != -1; i++)
+ printf(" %d: ix %d\n",i-3,dp[i]);
+#endif
+
+ /* Sort the list into ascending order */
+#define HEAP_COMPARE(A,B) (A < B)
+ HEAPSORT(int, dp + 3, dp[1]-3)
+#undef HEAP_COMPARE
- /* Increment counter */
- if (rpsh_inc(&counter, gc))
+#ifdef DEBUG2
+ printf(" After sorting:\n");
+ for (i = 3; dp[i] != -1; i++)
+ printf(" %d: ix %d\n",i-3,dp[i]);
+#endif
+
+ /* Delete any duplicates */
+ for (i = 3, j = i+1; ; j++) {
+ if (dp[i] != dp[j])
+ dp[++i] = dp[j];
+ if (dp[j] == -1)
break;
}
+ dp[1] = i;
+
+#ifdef DEBUG2
+ printf(" After de-duplication (length %d, alloc %d):\n",dp[1],dp[0]);
+ for (i = 3; dp[i] != -1; i++)
+ printf(" %d: ix %d\n",i-3,dp[i]);
+#endif
+
+ /* Filter fwd cells against emin/emax. */
+ /* (Don't bother for 1D, as there's no point in filling up the cache */
+ /* at this point, since 1D ins't participating in RAM management ?) */
+ if (s->fdi > 1) {
+ /* Allocate a temporary array to hold fwd cell emin */
+ if ((eminlist = (double *) rev_malloc(s, (dp[1]-3) * sizeof(double))) == NULL)
+ error("rspl malloc failed - rev create_nnrev_list emin array");
+ INCSZ(s, (dp[1]-3) * sizeof(double));
+
+ for (i = 0; i < (dp[1]-3); i++)
+ eminlist[i] = 1e200;
+
+ /* Get an fxcell for each fwd index, and compute emin & emax for this target. */
+ /* Tracl smallest maximum and record each fxcell emin */
+ emax = 1e200;
+ for (i = 3; dp[i] != -1; i++) {
+ fxcell *fc;
+ double em, ex;
+
+ fc = get_fxcell(s->rev.sb, dp[i], 1);
+
+ eminlist[i-3] = nn_grpgrp_est(s, &ex, &fc->g, &tx->g);
+ if (ex < emax)
+ emax = ex;
+
+ unget_fxcell(s->rev.cache, fc);
+ }
+
+#ifdef DEBUG2
+ printf(" Smallest emax = %f\n",emax);
+ for (i = 3; dp[i] != -1; i++)
+ printf(" %d: ix %d, emin %f\n",i-3,dp[i],eminlist[i-3]);
+#endif
+
+ /* Delete any fwd cells/indexes that have an emin > smallest emax */
+ for (i = j = 3; dp[j] != -1; j++) {
+ if (eminlist[j-3] <= emax)
+ dp[i++] = dp[j];
+ }
+ dp[i] = -1;
+ dp[1] = i;
+
+ free(eminlist);
+ DECSZ(s, sizeof(schbase));
+
+#ifdef DEBUG2
+ printf(" After removing too far cells (length %d, alloc %d):\n",i-3,dp[0]);
+ for (i = 3; dp[i] != -1; i++)
+ printf(" %d: ix %d\n",i-3,dp[i]);
+#endif
+ }
+
+ /* If the size of the list has reduced substatially, reclaim some memory */
+ if ((dp[1]+1) <= (dp[0]/2)) {
+ int ll = dp[0];
+ while (ll > (dp[1]+1))
+ ll /= 2;
+ ll *= 2;
+ DBG((" Reducing list allocation from %d to %d entries\n",dp[0],ll));
+ DECSZ(s, (dp[0] - ll) * sizeof(int));
+ if ((dp = (int *) rev_realloc(s, dp, sizeof(int) * ll)) == NULL)
+ error("rspl realloc failed - create_nnrev_list");
+ dp[0] = ll; /* New allocation */
+ }
+
+ /* Check if any neighbor lists are similar to the list we just created, */
+ /* so that we can merge similar lists, greatly reducing memory usage */
+ /* at the cost of slightly longer lists. */
+ /* Don't do this if this is a super-cell. */
+ /* [ This seems to increase nnrev fill time by about 5% ] */
+ if (tx->scell == NULL) {
+ DCOUNT(cc, MXRO, s->fdi, -1, -1, 2); /* bwd neighborhood offset counter */
+ int nn[MXRO];
+ int shlim, lnlim;
+ int sh, ln;
+ int bnix = -1, *blist = NULL, bwhgt = 0x7ffffff, bsh, bln;
+ int f, nix;
+
+ /* Set limits of an acceptable match at 2% short, 15% long */
+ /* This trades off list size against number of lists/memory */
+ /* i.e. a 10% rise in average list length for a 100 x reduction in */
+ /* number of lists. (vary lnlim for most effect) */
+ shlim = (2 * (dp[1]-3) + 50)/100;
+ lnlim = (15 * (dp[1]-3) + 50)/100;
+
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+
+ nix = tx->ix;
+ for (f = 0; f < s->fdi; f++) {
+ nn[f] = tx->gc[f] + cc[f];
+ if (nn[f] < 0 || nn[f] >= s->rev.res)
+ break; /* Out of bounds */
+ nix += cc[f] * s->rev.coi[f];
+ }
+ if (nix == tx->ix) /* Skip this cell */
+ goto next_neighbor;
+
+ /* If neighbor is in bounds and has a fwd cell list, */
+ /* check what sort of match it is to this list */
+ if (f >= s->fdi && s->rev.nnrev[nix] != NULL) {
+ int *np = s->rev.nnrev[nix];
+ int *shrecs = getsharelist(s, np);
+
+ if (shrecs != NULL) {
+ if (shrecs[2] == tx->ix) /* Already looked at this list */
+ goto next_neighbor;
+ shrecs[2] = tx->ix; /* Remember we've done this one */
+ }
+
+ /* See how much it is a super or sub-set */
+//printf("~1 checking ix %d against nix %d\n",tx->ix, nix);
+ if ((dp[1] - np[1]) > shlim
+ || (np[1] - dp[1]) > lnlim) {
+ goto next_neighbor; /* No possibility of being acceptable */
+ }
+
+ sh = ln = 0;
+ for (j = i = 3; dp[i] != -1 || np[j] != -1;) {
+
+//printf("1: dp[%d] %d - np[%d] %d\n",i,dp[i],j,np[j]);
+ while (np[j] != -1 && (dp[i] == -1 || dp[i] > np[j])) {
+ j++;
+ ln++;
+//printf("2: dp[%d] %d - np[%d] %d, ln %d\n",i,dp[i],j,np[j],ln);
+ if (ln > lnlim)
+ goto next_neighbor; /* No possibility of being acceptable */
+ }
+
+ while (dp[i] != -1 && (np[j] == -1 || dp[i] < np[j])) {
+ i++;
+ sh++;
+//printf("3: dp[%d] %d - np[%d] %d, sh %d\n",i,dp[i],j,np[j],sh);
+ if (sh > shlim)
+ goto next_neighbor; /* No possibility of being acceptable */
+ }
+
+ while (dp[i] != -1 && np[j] != -1 && dp[i] == np[j]) {
+ i++;
+ j++;
+//printf("4: dp[%d] %d - np[%d] %d\n",i,dp[i],j,np[j]);
+ }
+ }
+//printf("~1 len %d, short %d, long %d\n",dp[1]-3,sh,ln);
+
+ /* remember best similar list within our criteria */
+ if (sh <= shlim && ln <= lnlim) {
+ int whgt = 2 * sh + ln;
+ if (whgt < bwhgt) {
+ bnix = nix;
+ blist = np;
+ bwhgt = bwhgt;
+ bsh = sh;
+ bln = ln;
+ }
+ }
+ }
+ next_neighbor:;
+ DC_INC(cc);
+ }
+
+ /* Got a list we want to share with */
+ if (blist != NULL) {
+ int *shrecs = NULL;
+ int *exlist = NULL;
+
+ DBG((" Found similar existing list (short %d, long %d)\n",bsh,bln));
+
+#ifdef DEBUG2
+ printf(" Similar list (length %d, alloc %d):\n",blist[1]-3,blist[0]);
+// for (i = 3; blist[i] != -1; i++)
+// printf(" %d: ix %d\n",i-3,blist[i]);
+#endif
+ /* If the neighbor list is not a super-set */
+ if (bsh > 0) {
+
+ /* But new list is superset of neighbor list */
+ if (bln == 0) {
+ DBG((" Using new list to share\n"));
+
+ exlist = dp; /* Use our new list */
+ exlist[2] = blist[2]; /* Same sharers */
+ dp = NULL;
+
+ /* Free neighbor list */
+ free_indexlist(s, &blist);
+
+ /* Create superset list from new list and neighbor list */
+ } else {
+
+ DBG((" Creating superset list\n"));
+
+ for (j = i = 3; dp[i] != -1 || blist[j] != -1;) {
+
+ while (blist[j] != -1 && (dp[i] == -1 || dp[i] > blist[j])) {
+ add2indexlist(s, &exlist, blist[j], 0);
+ j++;
+ }
+
+ while (dp[i] != -1 && (blist[j] == -1 || dp[i] < blist[j])) {
+ add2indexlist(s, &exlist, dp[i], 0);
+ i++;
+ }
+
+ while (dp[i] != -1 && blist[j] != -1 && dp[i] == blist[j]) {
+ add2indexlist(s, &exlist, dp[i], 0);
+ i++;
+ j++;
+ }
+ }
+
+ exlist[2] = blist[2]; /* Same sharers */
+
+ /* Free neighbor list */
+ free_indexlist(s, &blist);
+
+ /* Done with list we created for this nnrev[] */
+ free_indexlist(s, &dp);
+ }
+
+ } else {
+ DBG((" Using existing list to share\n"));
+
+ exlist = blist; /* blist is already a super-set */
+ blist = NULL; /* Done with neighbor list */
+
+ /* Done with list we created for this nnrev[] */
+ free_indexlist(s, &dp);
+ }
+
+#ifdef DEBUG2
+ printf(" Superset list nnrev[%d] (length %d, alloc %d):\n",tx->ix,exlist[1]-3,exlist[0]);
+// for (i = 3; exlist[i] != -1; i++)
+// printf(" %d: ix %d\n",i-3,exlist[i]);
+#endif
+//if (s->fdi > 1 && (tx->ix == 19054 || tx->ix == 19055)) {
+//printf(" Superset list nnrev[%d] (length %d, alloc %d):\n",tx->ix,exlist[1]-3,exlist[0]);
+//for (i = 3; exlist[i] != -1; i++)
+// printf(" %d: ix %d\n",i-3,exlist[i]);
+//}
+
+ /* If this list has not been shared before, create share record for it */
+ if (getsharelist(s, exlist) == NULL)
+ add2sharelist(s, bnix, exlist);
+
+ /* Add this cell as a sharer */
+ add2sharelist(s, tx->ix, exlist);
+
+ /* Update pointers for all sharers of this (possibly new) list */
+ shrecs = getsharelist(s, exlist);
+//printf("Number shared now %d\n", shrecs[1]-3);
+ for (i = 3; shrecs[i] != -1; i++) {
+ s->rev.nnrev[shrecs[i]] = exlist;
+ }
+
+ } else {
+ DBG((" no matching existing list\n"));
+//printf(" no matching existing list\n");
+
+ /* Put list in place for target nnrev[]*/
+ s->rev.nnrev[tx->ix] = dp;
+ }
+ } else {
+
+ if (tx->scell != NULL) {
+
+ /* Put list in place for all nnrev[]'s covered by super-cell */
+ for (sp = tx->scell + 3; *sp != -1; sp++) {
+
+ /* Add this cell as a sharer */
+ add2sharelist(s, *sp, dp);
+
+ s->rev.nnrev[*sp] = dp;
+ }
+
+ } else {
+ /* Put list in place for target nnrev[]*/
+ s->rev.nnrev[tx->ix] = dp;
+ }
+ }
+
+ DBG(("create_nnrev_list done, total fwd cells = %d\n",s->rev.nnrev[tx->ix][1]-3));
}
-#endif /* NEVER */
-/* ========================================================== */
-/* reverse lookup acceleration structure initialisation code */
-
-/* The reverse lookup relies on a search of the fwd interpolation tables. */
-/* To eliminate out of gamut points quickly, to provide a starting point for */
-/* the search, and to guarantee that all possible reverse solutions are discovered, */
-/* a spatial indexing structure is used to provide a list of starting candidate */
-/* forward indexes for a given output value. (rev.rev[]) */
-/* The reverse structure contains an fdi dimensional cell grid, each element of the */
-/* cell grid holding the indexes of the forward interpolation grid, which intersect */
-/* that ranges of output values. A reverse cell will be empty if there is no */
-/* potential exact solution. */
-/* Note that unlike the forward grid which is composed of verticies, */
-/* this grid is composed of cells (there is an extra row allocated */
-/* during construction using verticies, that are not used when converted. */
-/* to cells) */
-/* For accelleration of the nearest lookup, a parallel reverse grid is */
-/* constructed that holds lists of forward grid cells that may hold the */
-/* nearest point within the gamut. These lists may be empty if we are within */
-/* gamut - ie. the rev.nnrev[] array is the complement of the rev.rev[] array. */
-/* During construction of rev.nnrev[], it is initially filled with lists for */
-/* the potential nearest cell list for each vertex (hence the extra rows allocated */
-/* for rev[] and nnrev[]), and these are then merged down to form the list */
-/* for each cell extent. The nnrev[] array is filled using a seed fill algorithm, */
-/* starting from the edges of the filled cells in rev[]. */
-/* Since many of the cells map to the same surface region, many of the fwd cell lists */
-/* are shared. */
-
-/* NOTE: that the nnrev accuracy doesn't seem as good as fill_nncell() ! */
-/* Could we fix this with better geometry calculations ??? */
-
-/* rev.nnrev[] cache entry record */
-struct _nncache{
- int min[MXRO]; /* bwd vertex extent covered by this list */
- int max[MXRO];
- int *rip; /* Fwd cell list */
- struct _nncache *next; /* Link list for this cache key */
-}; typedef struct _nncache nncache;
-
-/* Structure to hold prime seed vertex information */
-struct _primevx{
- int ix; /* Index of prime seed */
- int gc[MXRO]; /* coordinate of the prime seed vertex */
- struct _primevx *next; /* Linked list for final conversion */
- int *clist; /* Cell list generated for prime cell */
-}; typedef struct _primevx primevx;
-
-/* Structure to hold temporary nn reverse vertex propogation information */
-struct _propvx{
- int ix; /* Index of this secondary seed */
- int gc[MXRO]; /* coordinate of this secondary seed */
- int cix; /* Index of the closest surface nnrev vertex */
- double dsq; /* Distance to the closest point squared */
- int pass; /* Propogation pass */
- struct _propvx *next; /* Linked list for next seeds */
-}; typedef struct _propvx propvx;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* This is the routine used to fill nnrev[] cells on demand, */
+/* because s->rev.fastsetup is set. */
+/* This is similar to the code used in the normal case, except */
+/* we search the rev[] bxcell list rather than use the bxcell surface list */
+static void fill_nncell(
+ rspl *s,
+ int *co, /* Integer coords of cell to be filled */
+ int ix /* Index of cell to be filled */
+) {
+ int f, fdi = s->fdi;
+ DCOUNT(gg, MXRO, fdi, 0, 0, s->rev.res); /* search seed coordinate */
+ int i, six = -1, nn[MXRO];
+ double bdist = 1e200;
+ bxcell *tx, *ss;
+ DCOUNT(cc, MXRO, fdi, -1, -1, 2); /* bwd neighborhood offset counter */
+ int nix; /* Neighbor offset index */
+ bxcell *xlist = NULL; /* Linked list of cells being searched */
+ bxcell *xlistend = NULL; /* Last item on xlist */
+ bxcell *tlist; /* Linked list of cells being considered as soln. */
+ double emax; /* Current smallest estimated max weigted distance */
+
+ DBG(("fill_nncell: (triggered on-demand)\n"));
+
+ /* Allocate the bxcell hash index */
+ create_surfhash(s);
+
+ /* Locate a starting search cell. */
+ /* We use a simple full search of rev[] for the cell */
+ /* closest to our target. */
+ DC_INIT(gg);
+ for (i = 0; i < s->rev.no; i++) {
+ if (s->rev.rev[i] != NULL) {
+ double dist;
+ for (dist = 0.0, f = 0; f < fdi; f++) {
+ double tt = co[f] - gg[f];
+ dist += tt * tt;
+ }
+ if (dist < bdist) {
+ bdist = dist;
+ six = i;
+ for (f = 0; f < fdi; f++)
+ nn[f] = gg[f];
+ }
+ }
+ DC_INC(gg);
+ }
+ if (six < 0)
+ error("fill_nncell: rev[] is empty");
+
+ /* Create search seed cell */
+ ss = new_bxcell(s, six, nn, NULL, 0.0, NULL);
+ add_bxcell_hash(s, ss);
+
+ /* Create a target cell */
+ tx = new_bxcell(s, ix, co, ss, 0.0, NULL);
+ add_bxcell_hash(s, tx);
+
+ DBG((" Target ix = %d, co[] %s\n",ix,debPiv(fdi, tx->gc)));
+ DBG((" Search start ix = %d, co[] %s\n",six,debPiv(fdi, ss->gc)));
+//printf(" Target ix = %d, co[] %s\n",ix,debPiv(fdi, tx->gc));
+//printf(" Search start ix = %d, co[] %s\n",six,debPiv(fdi, ss->gc));
+
+ emax = 1e200; /* Smallest emax */
+ ss->tix = tx->ix; /* Mark this cell as being in search list */
+
+ /* Make start cell the only entry in the search list */
+ ss->xlist = NULL;
+ xlist = ss;
+ xlistend = ss;
+
+ /* Clear the solution list */
+ tlist = NULL;
+
+ /* While there are cells to search for solutions */
+ while (xlist != NULL) {
+ double em, ex;
+
+ ss = xlist; /* Remove next search cell from linked list */
+ xlist = xlist->xlist;
+
+ /* Check if this cell could be in solution */
+ em = nn_grpgrp_est(s, &ex, &tx->g, &ss->g);
+ ss->emin = em;
+
+ DBG(("Searching rev[%d] co %s, em %f, ex %f\n",ss->ix, debPiv(s->fdi, ss->gc), em, ex));
+//printf("Searching rev[%d] co %s, em %f, ex %f\n",ss->ix, debPiv(s->fdi, ss->gc), em, ex);
+
+ if (em < emax) { /* Yes */
+
+ /* Add it to the solution list */
+ ss->tlist = tlist;
+ tlist = ss;
+
+ // copy rev[] list to ss->sl
+ copy_indexlist(s, &ss->sl, s->rev.rev[ss->ix]);
+
+ DBG(("Adding %d to solution list\n",ss->ix));
+//printf("Adding %d to to solution list\n",ss->ix);
+
+ /* Update smallest maximum */
+ /* (Will cull existing bxcell solutions with emin > emax later) */
+ if (ex < emax)
+ emax = ex;
+
+ /* Explore all neighbours, and add any surface cells that haven't been */
+ /* searched for this target yet. */
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ bxcell *nbx;
+
+ nix = ss->ix;
+ for (f = 0; f < fdi; f++) {
+ nn[f] = ss->gc[f] + cc[f];
+ if (nn[f] < 0 || nn[f] >= s->rev.res)
+ break; /* Out of bounds */
+ nix += cc[f] * s->rev.coi[f];
+ }
+ if (f < fdi || nix == ss->ix) {
+//printf("Rejecting search neigbor co %s because out of bounds or current cell\n",debPiv(s->fdi,nn));
+ goto next_neighbor;
+ }
+
+ /* Can only search within filled rev[] cells */
+ if (s->rev.rev[nix] == NULL) {
+ goto next_neighbor;
+ }
+
+ /* If neighbor is in bounds, and a surface bxcell*/
+ {
+ /* Make sure we have a bxcell for the neighbor */
+ if ((nbx = get_surface_bxcell(s, nix)) == NULL) {
+ nbx = new_bxcell(s, nix, nn, NULL, 0.0, NULL);
+ add_bxcell_hash(s, nbx);
+ }
+
+ /* If not already in search list */
+ if (nbx->tix != tx->ix) {
+// DBG(("Adding search neigbor nnrev[%d] co %s to search list\n",nbx->ix, debPiv(s->fdi, nbx->gc)));
+//printf("Adding search neigbor nnrev[%d] co %s to search list\n",nbx->ix, debPiv(s->fdi, nbx->gc));
+ /* Add neigbor to end of search list */
+ nbx->tix = tx->ix; /* Is now in search list */
+ nbx->xlist = NULL;
+ if (xlist == NULL)
+ xlist = nbx;
+ else
+ xlistend->xlist = nbx;
+ xlistend = nbx;
+ }
+//else
+//printf("Rejecting search neigbor nnrev[%d] co %s because already in list\n",nbx->ix, debPiv(s->fdi, nbx->gc));
+ }
+ next_neighbor:;
+ DC_INC(cc);
+ }
+ }
+//else
+//printf("Rejected rev[%d] co %s, because em %f >= emax %f\n",ss->ix, debPiv(s->fdi, ss->gc), em, emax);
+ }
+
+ if (tlist == NULL)
+ error("fill_nncell: search for rev[] cells failed");
+
+//printf("Got solution list, filling in nnrev[] cell\n");
+ /* Create the nnrev[] list from the candidate bxcell solutions */
+ create_nnrev_list(s, tx, tlist, emax);
+
+//printf("nnrev[%d] list length = %d\n",tx->ix,s->rev.nnrev[tx->ix][1]-3);
+
+ /* Free up bxcell hash index and all bxcell's we've created */
+ free_surfhash(s, 1);
+
+ DBG(("fill_nncell done\n"));
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Associated sub-simplex tables. For a given base vertex with a given fwd */
+/* access flags FLV(), create is a pointer to a list of sub-simplex verticies */
+/* offset from the base vertex that the base vertex is part of, in all possible */
+/* directions. We do all possible directions to make the bxcell triangle */
+/* search symetrical, and searching triangles using points outside */
+/* the bxcell list seems to actually speed it up (by culling more effectively) */
+
+typedef struct {
+ int pos; /* nz if this is a ssimplex that is only in the +ve direction */
+ int ee;
+ int goffs[MXDI+1]; /* Offsets to sub-simplex verticies within grid in simplex order. */
+} assinfo;
+
+typedef struct {
+ int sdi; /* Sub dimensionality */
+ int no; /* Number of sub-simplexes in list */
+ assinfo *ti; /* Per sub-simplex info array */
+} assdire;
+
+#if (FL_BITS != 3)
+#error FL_BITS is not 3!
+#endif
+
+/* init the triangle/edge directory list and related assinfo tables */
+/* sdi = 2 for triangles, 1 for edges */
+static void init_assdir(rspl *s, assdire **passdir, int sdi) {
+ assdire *assdir;
+ int i, j, k;
+ int e, ee, di = s->di;
+ int dirsize;
+ DCOUNT(cc, MXRI, di, -1, -1, 2); /* Clipping values for each dim */
+ ssxinfo *xip; /* Pointer to sub-simplex info structure */
+
+ DBG(("init_assdir called, di = %d\n",di));
+
+ dirsize = (1 << (FL_BITS * di));
+
+ if ((assdir = (assdire *) rev_calloc(s, dirsize, sizeof(assdire))) == NULL)
+ error("rspl malloc failed - assdir");
+ INCSZ(s, dirsize * sizeof(assdire));
+
+ assdir->sdi = sdi;
+ xip = &s->rev.sspxi[sdi];
+
+#ifdef NEVER
+ printf("simplex dim %d:\n",xip->sdi);
+ for (i = 0; i < xip->nospx; i++) {
+ printf("offs = %s\n", debPiv(sdi+1, xip->spxi[i].offs));
+ printf("goffs = %s\n", debPiv(sdi+1, xip->spxi[i].goffs));
+ }
+#endif
+
+ /* For each possible clip combination */
+ /* (where < 0 == clipping lower edge, > 0 == clipping upper edge */
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ int trilaloc, trillen;
+ assinfo *trilist;
+
+ /* Start a new table, allocate the maximum possible number of entries. */
+ trilaloc = (1 << di) * xip->nospx;
+ if ((trilist = (assinfo *) rev_calloc(s, trilaloc, sizeof(assinfo))) == NULL)
+ error("rspl malloc failed - trilist");
+ INCSZ(s, trilaloc * sizeof(assinfo));
+ trillen = 0;
+
+ /* For all cube directions from base, 0 = +ve, 1 = -ve */
+ for (ee = 0; ee < (1<<di); ee++) {
+
+ /* For all the sub-simplexes in a cube */
+ for (i = 0; i < xip->nospx; i++) {
+ int gotbase = 0;
+
+ /* Offset the sub-simplex by the direction, and check that the */
+ /* base vertex is part of it. */
+ trilist[trillen].ee = ee;
+ trilist[trillen].pos = (ee == 0);
+ for (j = 0; j < (sdi+1); j++) {
+ trilist[trillen].goffs[j] = xip->spxi[i].goffs[j] - s->g.hi[ee];
+ if (trilist[trillen].goffs[j] == 0) /* Base vertex is present */
+ gotbase = 1;
+ }
+ if (!gotbase) {
+ continue;
+ }
+
+ /* See if the direction of each vertex of the sub-simplex is */
+ /* compatible with the clipping. */
+ for (j = 0; j < (sdi+1); j++) {
+ for (e = 0; e < di; e++) {
+ if (xip->spxi[i].offs[j] & (1<<e)) {
+
+ if ((cc[e] < 0 && (ee & (1<<e)) != 0)
+ || (cc[e] > 0 && (ee & (1<<e)) == 0)) {
+ break; /* not compatible */
+ }
+ }
+ }
+ if (e < di) { /* Not compatible */
+ break;
+ }
+ }
+ if (j < (sdi+1)) {
+ continue; /* Not compatible */
+ }
+
+ /* We end up with aliases due to the sspxi having all */
+ /* sub-simplexes within a cube, so see if we already */
+ /* created this one. */
+ for (k = 0; k < trillen; k++) {
+ for (j = 0; j < (sdi+1); j++) {
+ if (trilist[k].goffs[j] != trilist[trillen].goffs[j])
+ break;
+ }
+ if (j >= (sdi+1))
+ break; /* Redundant - don't add this point */
+ }
+ if (k < trillen) {
+ continue; /* Skip redundant combination */
+ }
+
+//printf(" Clip %s off %d tri %d goffs = %s\n", debPiv(di, cc), ee, trillen, debPiv(sdi+1, trilist[trillen].goffs));
+ trillen++;
+ }
+ }
+
+//printf("Got %d triangles for cc %s\n", trillen, debPiv(di, cc));
+
+ /* Add table to all matching combination of FLV() */
+ for (i = 0; i < dirsize; i++) {
+ for (e = 0; e < di; e++) {
+ int fl = (i >> (3 * e)) & 7;
+ if (! /* NOT: */
+ ((cc[e] > 0 && fl == 0) /* Top edge clip and on top edge */
+ || (cc[e] < 0 && fl == 4) /* Bottom edge clip and on bottom edge */
+ || (cc[e] == 0 && fl != 0 && fl != 4))) /* No clipping and in middle */
+ break; /* Not a match */
+ }
+ if (e >= di) { /* Table matches this FLV() */
+ assdir[i].no = trillen;
+ assdir[i].ti = trilist;
+ }
+ }
+ DC_INC(cc); /* Next clip combination */
+ }
+
+#ifdef NEVER
+ /* Check that there is a list for every flag value */
+ for (i = 0; i < dirsize; i++) {
+ if (assdir[i].no == 0)
+ error("init_assdir has fl %d entry with no sub-simplexes",i);
+ else
+ printf("fl %d has %d triangles\n",i,assdir[i].no);
+ }
+#endif
+
+ *passdir = assdir;
+}
+
+static void free_assdir(rspl *s, assdire *assdir) {
+ int i, j;
+ int e, ee, di = s->di;
+ int sdi = assdir->sdi;
+ int dirsize = (1 << (FL_BITS * di));
+ int trilaloc = (1 << di) * s->rev.sspxi[sdi].nospx;
+
+ for (i = 0; i < dirsize; i++) {
+ assinfo *trilist;
+
+ if ((trilist = assdir[i].ti) == NULL)
+ continue;
+
+ /* Free all aliases of list */
+ for (j = i; j < dirsize; j++) {
+ if (trilist == assdir[j].ti) {
+ assdir[j].ti = NULL;
+ }
+ }
+ free(trilist);
+ DECSZ(s, trilaloc * sizeof(assinfo));
+ }
+ free(assdir);
+ DECSZ(s, dirsize * sizeof(assdire));
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Solve the 2x2 simultaneous linear equations A.X = B */
+static int solve_se_2x2(double **ta, double *tb) {
+ double b[2] = { tb[0], tb[1] };
+ double det;
+ int rv;
+
+ det = (ta[0][0] * ta[1][1] - ta[0][1] * ta[1][0]);
+
+ if (fabs(det) < 1e-20)
+ return 1;
+
+ det = 1.0/det;
+ tb[0] = det * ( ta[1][1] * b[0] - ta[0][1] * b[1]);
+ tb[1] = det * (-ta[1][0] * b[0] + ta[0][0] * b[1]);
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef CHECK_NNLU
+
+/* Debug code */
+
+static int debug(int ix) {
+ if (
+ (ix == 619 || ix == 618 || ix == 329)
+ || (ix == 330 || ix == 329 || ix == 312)
+ || (ix == 619 || ix == 329 || ix == 312)
+ || (ix == 329 || ix == 312 || ix == 23)
+ || (ix == 329 || ix == 23 || ix == 22)
+ || (ix == 40 || ix == 23 || ix == 22)
+ )
+ return 1;
+ return 0;
+}
+
+static int debug2(int *ix) {
+ if (
+ (ix[0] == 619 && ix[1] == 618 && ix[2] == 329)
+ || (ix[0] == 330 && ix[1] == 329 && ix[2] == 312)
+ || (ix[0] == 619 && ix[1] == 329 && ix[2] == 312)
+ || (ix[0] == 329 && ix[1] == 312 && ix[2] == 23)
+ || (ix[0] == 329 && ix[1] == 23 && ix[2] == 22)
+ || (ix[0] == 40 && ix[1] == 23 && ix[2] == 22)
+ )
+ return 1;
+ return 0;
+}
+
+#endif /* CHECK_NNLU */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#ifdef REVVRML /* Plotting routine declarations */
+
+static void plot_bxfwcells(rspl *s, int dobxcells, int dofwcells, int dofwlabels);
+
+static void plot_tri_check(rspl *s, int dobxcells, int dowait, bxcell *bx, int vtxix,
+ int trii, int triix[3], int nvtxix, int sorv, int wsrv, int shdwd,
+ double v[MXRI+1][MXRO], double de[MXRO], double pv[MXRO], double xv[MXRO]);
+
+static void plot_vtx_surface(rspl *s, int dovtxlabels, int dodeleted, int doadded,
+ int dopres, int dooil, int dobxcells, int dowait, vtxcache *vc, assdire *edgdir);
+
+static void plot_touched_bxcells(rspl *s, int bxix);
+
+static void plot_fxcell_surface(rspl *s, int dofclabels, int dobxcells, int dowait);
+
+#endif /* REVVRML */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ The basic strategy to thin the gamut surface as much as possible
+ to reduce the nnrev[] list size for best memory consuption and
+ rev lookup speed relies on being able to decide if a vertx
+ is inside or on the surface of the gamut. A simple and definitive
+ topological rule hasn't been forthcoming, so a simpler heursitic
+ of visiblilty from a singe internal "focal" point is currently used.
+ calc_ocent() attempts to choose a point with best visibilit of
+ all the gamut surfaces, since any self-shadowing results in
+ gamut surface holes.
+
+ Improvements would be to create per-axis mappings (and separate
+ the shadow vertex locations from the real ones) to re-shape
+ the gamut into a squere as much as possible.
+ Multiple external focal points could be used,
+ a vertex being shadowed only when it can't be "seen" by any
+ external focal point. It's hard to figure how to make the latter
+ fast enough to be useful though, unless some breakthrough
+ in the algorithm or spatial data structure can be developed.
+
+ The code is still slower than desired. A possible avenue for
+ improving the thinning would be to add an explicit triangle
+ structure (similar to gamut ?), add a suitable spatial
+ accelleration structure for shadow testing (BSP tree ??),
+ and build the gamut surface incrementally from existing
+ furthest points.
+*/
+
+/* Struct to slice locus points */
+struct _slpoint {
+ double v[MXRO]; /* Point location */
+ double rad; /* Distance from ccent */
+
+ double cvec[MXRO]; /* Vector from this point to ccent */
+ double len; /* Length of segment, -1 if no good */
+ double trad; /* Trial center point to this v[] radius */
+}; typedef struct _slpoint slpoint;
+
+/* Center finding context */
+struct _ocenctx {
+ rspl *s;
+ int ares; /* angle resolution */
+ slpoint *p[MXRO]; /* Slice locus points */
+ double ccent[MXRO]; /* Construction center point */
+ int debug;
+}; typedef struct _ocenctx ocenctx;
+
+/* Given a set of slice locus points and a proposed center point, */
+/* compute the weighted averag of the orthogonality of the point */
+/* to each locus line segment. (smaller is better) */
+static double aorthog(void *_ctx, double *cent) {
+ ocenctx *ctx = (ocenctx *) _ctx;
+ rspl *s = ctx->s;
+ int f, ff, fdi = s->fdi;
+ int aa, ares = ctx->ares;
+ double tcent[MXRO];
+ double ang, aang = 0.0;
+ int naang = 0;
+
+ if (ctx->debug) printf("aorthog called with cent %s\n",debPdv(fdi,cent));
+
+ for (ff = 0; ff < fdi; ff++) {
+ if (ctx->debug) printf(" Axis %d\n",ff);
+
+ for (f = 0; f < fdi; f++)
+ tcent[f] = cent[f];
+ /* Flatten the points to lie on the notional center */
+ tcent[ff] = ctx->ccent[ff];
+
+ for (aa = 0; aa < ares; aa++) {
+ double trad, nrad;
+ double cvec[MXRO], dot;
+
+ if (ctx->p[ff][aa].len < 0.0)
+ continue;
+
+ if (aa == 0) {
+ /* Compute normalize vector from cent to locus to this point */
+ trad = 0.0;
+ for (f = 0; f < fdi; f++) {
+ double tt = tcent[f] - ctx->p[ff][aa].v[f];
+ trad += tt * tt;
+ }
+ trad = sqrt(trad);
+ } else { /* Was computed by previous */
+ trad = ctx->p[ff][aa].trad;
+ }
+
+ /* Compute normalize vector from tcent to locus to next point */
+ nrad = 0.0;
+ for (f = 0; f < fdi; f++) {
+ cvec[f] = tcent[f] - ctx->p[ff][aa+1].v[f];
+ nrad += cvec[f] * cvec[f];
+ }
+ nrad = ctx->p[ff][aa+1].trad = sqrt(nrad);
+
+ /* Normalized difference in distance over length */
+ /* Compute dot product of cv and segment vector */
+ ang = fabs(trad - nrad)/ctx->p[ff][aa].len;
+
+ if (ctx->debug) printf(" aa %d: trad %f nrad %f, diff %f, len %f, ang %f\n",aa,trad,nrad,fabs(trad - nrad),ctx->p[ff][aa].len,ang);
+
+ /* Compute dot of next point vector from trial center */
+ /* with vector from construction center, to detect */
+ /* if the trial has wandered outside of gamut. */
+ dot = 0.0;
+ for (f = 0; f < fdi; f++)
+ dot += cvec[f] * ctx->p[ff][aa+1].cvec[f];
+
+ if (dot < 0.0) {
+ if (ctx->debug) printf(" dot is %f\n",dot);
+ ang = 50.0; /* Big value */
+ } else {
+ ang = pow(ang, 50.0); /* Weight high angles */
+ }
+
+ if (ang > aang)
+ aang = ang;
+
+ aang += ang;
+ naang++;
+ }
+ }
+ aang /= (double)naang;
+
+ if (ctx->debug) printf(" returning %f\n",aang);
+
+ return aang;
+}
+
+/* Determine a gamut center point, for surface triangle shadow testing. */
+/* We assume that rev[] has been setup. */
+/* The idea is to locate a point that best "sees" all internal */
+/* surface of the gamut. */
+static void calc_ocent(rspl *s) {
+ int i, j, aa, mm;
+ int f, ff, fdi = s->fdi;
+ int rgres = s->rev.res; /* number of bwd cells */
+ double minmax[2][MXRO][MXRO]; /* Range min/max points for each axis */
+ float *gp, *ep;
+ int midix[MXDO]; /* Middle rev[] index */
+ double mid[MXRO]; /* Middle of midix[] */
+ double ss[MXRO];
+ ocenctx ctx; /* Context */
+ double atanscale;
+
+ /* Scan the forward array for the min and max points of each axis */
+ for (f = 0; f < fdi; f++) {
+ minmax[0][f][f] = 1e30;
+ minmax[1][f][f] = -1e30;
+ }
+
+ /* Scan the Grid for min/max values */
+ for (gp = s->g.a, ep = s->g.a + s->g.no * s->g.pss; gp < ep; gp += s->g.pss) {
+ for (ff = 0; ff < fdi; ff++) {
+ if (minmax[0][ff][ff] > gp[ff]) {
+ for (f = 0; f < fdi; f++)
+ minmax[0][ff][f]= gp[f];
+ }
+ if (minmax[1][ff][ff] < gp[ff]) {
+ for (f = 0; f < fdi; f++)
+ minmax[1][ff][f] = gp[f];
+ }
+ }
+ }
+
+ if (fdi == 1) {
+ for (f = 0; f < fdi; f++)
+ s->rev.ocent[f] = 0.5 * (minmax[0][0][f] + minmax[1][0][f]);
+ DBG(("calc_ocent: got ocent = %s\n",debPdv(fdi,s->rev.ocent)));
+ return;
+ }
+
+ /* Aprox. mid point of gamut from average of min/max points */
+ for (f = 0; f < fdi; f++)
+ ctx.ccent[f] = 0.0;
+ for (ff = 0; ff < fdi; ff++) {
+ for (f = 0; f < fdi; f++) {
+ if (f == ff)
+ continue;
+ for (mm = 0; mm < 2; mm++)
+ ctx.ccent[f] += minmax[mm][ff][f];
+ }
+ }
+ for (f = 0; f < fdi; f++)
+ s->rev.ocent[f] = ctx.ccent[f] /= ((fdi-1) * 2.0);
+
+ DBG(("calc_ocent: ccent = %s\n",debPdv(fdi,ctx.ccent)));
+
+ /* If it's all to hard ... */
+ if (fdi != 3) {
+ return;
+ }
+
+ /* Index of data mid point in rev[] grid */
+ for (f = 0; f < fdi; f++) {
+ midix[f] = (int)((ctx.ccent[f] - s->rev.gl[f])/s->rev.gw[f] + 0.5);
+ mid[f] = (midix[f]+0.5) * s->rev.gw[f] + s->rev.gl[f];
+ }
+
+ /* Array for each slice values at angle (+ repeat at end) */
+ ctx.debug = 0;
+ ctx.s = s;
+ ctx.ares = 20;
+ atanscale = ctx.ares/(2.0 * DBL_PI);
+ for (ff = 0; ff < fdi; ff++) {
+ if ((ctx.p[ff] = (slpoint *)rev_calloc(s, ctx.ares+1,sizeof(slpoint))) == NULL)
+ error("rspl malloc failed - calc_ocent arrays");
+ INCSZ(s, (ctx.ares+1) * sizeof(slpoint));
+ }
+
+//printf("~1 locating center point\n");
+
+ /* Set initial radius values */
+ for (aa = 0; aa < ctx.ares; aa++) {
+ for (ff = 0; ff < fdi; ff++)
+ ctx.p[ff][aa].rad = -1.0;
+ }
+
+ /* Take three slices through the rev[] array, plotting */
+ /* the maximum circumference for the slice */
+
+ /* For the axis we're slicing */
+ for (ff = 0; ff < fdi; ff++) {
+ DCOUNT(cc, MXRO, 2, 0, 0, rgres); /* Counter through bwd cells */
+ double vv[MXRO];
+ int aa;
+
+//printf(" slice axis %d\n",ff);
+
+ /* Scan this slice of rev[] */
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ int ix;
+ int slix[2]; /* Indexes in slice direction */
+ int *rp;
+ int co[MXRO];
+
+ /* Compute bx index */
+ ix = 0;
+ for (j = f = 0; f < fdi; f++) {
+ if (f == ff)
+ co[f] = midix[f];
+ else {
+ slix[j] = f;
+ co[f] = cc[j++];
+ }
+ ix += co[f] * s->rev.coi[f];
+ }
+//printf(" bx %d, %d ix %d\n",co[0],co[1],co[2],ix);
+
+ if (s->rev.rev[ix] == NULL) {
+//printf(" rev is empty\n");
+ goto next_bx;
+ }
+
+ /* For all the vertex values in bx rev[] */
+ for (rp = s->rev.rev[ix]+3; *rp != -1; rp++) {
+ float *fcb = s->g.a + *rp * s->g.pss;
+ double x, y, rad, ang;
+
+//printf(" vtx %d\n",*rp);
+ /* Ignore over ink limit values */
+ if (s->limiten && fcb[-1] > s->limitv)
+ continue;
+
+ /* Compute radius and normalize */
+ x = fcb[slix[0]] - ctx.ccent[slix[0]];
+ y = fcb[slix[1]] - ctx.ccent[slix[1]];
+ rad = sqrt(x * x + y * y);
+ if (rad < EPS)
+ continue;
+
+ /* Quantized angle this point is at */
+ ang = atanscale * atan2(y, x);
+ aa = (int)floor(ang);
+ if (aa < 0)
+ aa += ctx.ares;
+ if (aa >= ctx.ares)
+ aa -= ctx.ares;
+
+//printf(" slice %d vtx %f %f %f rad %f, ang %f aa %d\n", ff, fcb[0], fcb[1], fcb[2], rad, ang, aa);
+
+ if (rad > ctx.p[ff][aa].rad) {
+ ctx.p[ff][aa].rad = rad;
+
+ for (f = 0; f < fdi; f++) {
+ ctx.p[ff][aa].v[f] = fcb[f];
+ }
+ /* Flatten the points to lie on the notional center */
+ ctx.p[ff][aa].v[ff] = ctx.ccent[ff];
+ }
+ }
+ next_bx:;
+ DC_INC(cc);
+ }
+
+ /* Repeat first in extra at end */
+ ctx.p[ff][ctx.ares] = ctx.p[ff][0]; /* Structure copy */
+ }
+
+ /* Pre-compute point to point info to speed optimization */
+ for (ff = 0; ff < fdi; ff++) {
+ for (aa = 0; aa < ctx.ares; aa++) {
+ double len = 0.0;
+
+ for (f = 0; f < fdi; f++)
+ ctx.p[ff][aa+1].cvec[f] = ctx.ccent[f] - ctx.p[ff][aa].v[f];
+
+ for (f = 0; f < fdi; f++) {
+ double tt = ctx.p[ff][aa+1].v[f] - ctx.p[ff][aa].v[f];
+ len += tt * tt;
+ }
+ if (len < EPS)
+ ctx.p[ff][aa].len = -1.0;
+ else
+ ctx.p[ff][aa].len = sqrt(len);
+ }
+ }
+
+ /* Locate center point that maximised the orthogonallity to each */
+ /* slice segment. This should maximize visibility of the inner of the */
+ /* gamut surface, for shadow testing. */
+ for (f = 0; f < fdi; f++)
+ ss[f] = 5.0;
+
+ /* return 0 on sucess, 1 on failure due to excessive itterations */
+ if (powell(NULL, fdi, s->rev.ocent, ss, 1e-3, 500, aorthog, (void *)&ctx, NULL, NULL)) {
+ printf("calc_ocent powell failed\n");
+ for (f = 0; f < fdi; f++)
+ s->rev.ocent[f] = ctx.ccent[f];
+ }
+
+// ctx.debug = 1;
+// printf("Final angle = %f\n", aorthog(&ctx, ctx.ccent));
+
+#ifdef REVVRML /* Plotting routine declarations */
+ /* Diagnostic - dump the gamut slice locii */
+ {
+ vrml *wrl;
+ double grey[3] = { 0.5, 0.5, 0.5 };
+ double white[3] = { 1.0, 1.0, 1.0 };
+ double red[3] = { 0.8, 0.1, 0.1 };
+ double green[3] = { 0.1, 1.0, 0.1 };
+ double blue[3] = { 0.1, 0.1, 0.8 };
+ double *rgb[3] = { red, green, blue };
+
+ wrl = new_vrml("section", 0, vrml_lab);
+ wrl->add_marker(wrl, s->rev.ocent, NULL, 1.0);
+
+ /* Show vertex labels */
+ for (ff = 0; ff < fdi; ff++) {
+ char index[100];
+
+ for (aa = 0; aa < ctx.ares; aa++) {
+ if (ctx.p[ff][aa].rad > 0) {
+ sprintf(index, "%d:%d",ff,aa);
+ wrl->add_text(wrl, index, ctx.p[ff][aa].v, white, 1.0);
+ }
+ }
+ }
+
+ /* Axis we're slicing */
+ for (ff = 0; ff < fdi; ff++) {
+ int vix[100];
+
+ for (aa = 0; aa < ctx.ares; aa++) {
+ if (ctx.p[ff][aa].rad > 0)
+ vix[aa] = wrl->add_vertex(wrl, 0, ctx.p[ff][aa].v);
+ }
+ vix[aa] = vix[0];
+
+ for (aa = 0; aa < ctx.ares; aa++) {
+ if (ctx.p[ff][aa].rad > 0
+ && ctx.p[ff][aa+1].rad > 0)
+ wrl->add_col_line(wrl, 0, vix + aa, rgb[ff]);
+ }
+ }
+ wrl->make_lines_vc(wrl, 0, 0.0);
+ printf("Created %s\n",wrl->name);
+ wrl->del(wrl);
+ }
+#endif /* REVVRML */
+
+ /* Free up the context data */
+ for (ff = 0; ff < fdi; ff++) {
+ free(ctx.p[ff]);
+ DECSZ(s, (ctx.ares+1) * sizeof(slpoint));
+ }
+
+ DBG(("calc_ocent: got ocent = %s\n",debPdv(fdi,s->rev.ocent)));
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Initialise the rev Second section acceleration information. */
/* This is called when it is discovered on a call that s->rev.rev_valid == 0 */
static void init_revaccell(
@@ -5132,39 +8787,101 @@ rspl *s
int fdi = s->fdi;
int gno = s->g.no;
int rgno = s->rev.no;
- int argres = s->rev.ares; /* Allocation rgres, = no bwd cells +1 */
- int rgres = s->rev.res; /* no bwd cells */
+ int rgres = s->rev.res; /* number of bwd cells */
int rgres_1 = rgres-1; /* rgres -1 == maximum base coord value */
schbase *b = s->rev.sb; /* Base search information */
- char *vflag = NULL; /* Per vertex flag used during construction of nnrev */
+ char *vflag = NULL; /* Per bwd vertex flag used during construction of nnrev */
+ /* 0 nnrev[] cell empty, not surface */
+ /* 1 nnrev[] done/don't fill, not surface */
+ /* 2 nnrev[] cell empty, on surface */
+ /* 3 nnrev[] done, on surface */
+ /* 1X nnrev[] contains ink limited fwcells */
+ /* Note that bit 1 can be set for cells that are not */
+ /* to be explored because they are in the gamut interior, */
+ /* and because they have already been added to the seedlist. */
float *gp; /* Pointer to fwd grid points */
- primevx *plist = NULL, *ptail = NULL; /* Prime seed list for last pass */
- propvx *alist = NULL; /* Linked list of active secondary seeds */
- propvx *nlist = NULL; /* Linked list of next secondary seeds */
- DCOUNT(gg, MXRO, fdi, 0, 0, argres);/* Track the prime seed coordinate */
- DCOUNT(cc, MXRO, fdi, -1, -1, 2); /* Neighborhood offset counter */
- int nn[MXRO]; /* Neighbor coordinate */
- int pass = 0; /* Propogation pass */
- int nncsize; /* Size of the rev.nnrev construction cache index */
- nncache **nnc; /* nn cache index, used during construction of nnrev */
- unsigned hashk; /* Hash key */
- nncache *ncp; /* Hash entry pointer */
- int nskcells = 0; /* Number of skiped cells (debug) */
-#ifdef DEBUG
- int cellinrevlist = 0;
- int fwdcells = 0;
+
+ DCOUNT(gg, MXRO, fdi, 0, 0, rgres); /* Track the prime seed coordinate */
+ int nn[MXRO]; /* bwd neighbor coordinate */
+
+ vtxcache vc; /* List + cache of vertexes being processed */
+ tricache tc; /* cache of surface triangles that have been processed */
+ tricache stc; /* small cache of surface triangles that have been processed */
+ bxcell *bx, *nbx, **pbx;
+ bxcell *xlist = NULL; /* Linked list of added surface bxcells */
+ assdire *tridir = NULL; /* Triangle tables */
+ assdire *edgdir = NULL; /* Edge tables */
+ double **cla = NULL; /* Line LHS implicit equation matrix [fdi][fdi+1] */
+ double *ta[MXRO], TA[MXRO][MXRO]; /* temp for intersection solving */
+
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ /* Some statistics */
+ unsigned long smsec;
+ int nskcells = 0; /* Number of skipped cells because over ink limit (debug) */
+ int nascells = 0; /* Number of added surface cells */
+ int nrscells = 0; /* Number of removed surface cells */
+ int naoulvtxs = 0; /* Number of added over ink limit vertexes */
+ int revcells = 0; /* Non-empty rev[] cells */
+ int revcelldepth = 0; /* Sum of rev[] list lengths */
+ int ingamutcells = 0; /* No of rev[] cells not on surface */
+ int surfcells = 0; /* No. surface cells */
+ int emptycells = 0; /* No. empty cells */
+ int nnrevcells = 0; /* Non-empty nnrev[] cells */
+ int nnrevcellsearch = 0; /* Sum of number of surface cells searched */
+ int nnsinglefill = 0; /* Number of nnrev[] cells seeded singly */
+ int nnsuperfill = 0; /* Number of nnrev[] cells seeded using supercell */
+ int nnrevcelldepth = 0; /* Sum of nnrev[] list lengths */
+ int nnmxrevcelldepth = 0; /* Maximum nnrev[] list lengths */
+ int nnrevshare = 0; /* Sum of nnrev[] list reference counts */
#endif
DBG(("init_revaccell called, di = %d, fdi = %d, mgres = %d\n",di,fdi,(int)s->g.mres));
- if (!s->rev.fastsetup) {
- /* Temporary per bwd vertex/cell flag */
- if ((vflag = (char *) calloc(rgno, sizeof(char))) == NULL)
- error("rspl malloc failed - rev.vflag points");
- INCSZ(s, rgno * sizeof(char));
+ if (fdi > 1 && s->verbose)
+ fprintf(stdout, "%cInitializing nnrev arrays...\n",cr_char);
+
+ /* Add this instance into memory management */
+ if (s->rev.rev_valid == 0 && di > 1) {
+ rev_struct *rsi;
+ size_t ram_portion = g_avail_ram;
+
+ /* Add into linked list */
+ s->rev.next = g_rev_instances;
+ g_rev_instances = &s->rev;
+
+ /* Aportion the memory, and reduce cache if it is over new limit. */
+ g_no_rev_cache_instances++;
+ ram_portion /= g_no_rev_cache_instances;
+ for (rsi = g_rev_instances; rsi != NULL; rsi = rsi->next) {
+ revcache *rc = rsi->cache;
+
+ rsi->max_sz = ram_portion;
+ while (rc->nunlocked > 0 && rsi->sz > rsi->max_sz) {
+ if (decrease_revcache(rc) == 0)
+ break;
+ }
+//printf("~1 rev instance ram = %d MB\n",rsi->sz/1000000);
+ }
+
+ if (s->verbose)
+ fprintf(stdout, "%cThere %s %d rev cache instance%s with %lu Mbytes limit\n",
+ cr_char,
+ g_no_rev_cache_instances > 1 ? "are" : "is",
+ g_no_rev_cache_instances,
+ g_no_rev_cache_instances > 1 ? "s" : "",
+ (unsigned long)ram_portion/1000000);
}
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ smsec = msec_time();
+#endif
+
+ /* Temporary per bwd vertex/cell flag for nn setup */
+ if ((vflag = (char *) rev_calloc(s, rgno, sizeof(char))) == NULL)
+ error("rspl malloc failed - rev.vflag points");
+ INCSZ(s, rgno * sizeof(char));
+
/*
* The rev[] and nnrev[] grids contain pointers to lists of grid cube base indexes.
* If the pointer is NULL, then there are no base indexes in that list.
@@ -5196,44 +8913,64 @@ rspl *s
}
/* We then fill in the in-gamut reverse grid lookups, */
- /* and identify nnrev prime seed verticies */
+ /* and identify nnrev prime seed verticies to put in the surface bxcells. */
DBG(("filling in rev.rev[] grid\n"));
/* To create rev.rev[], for all fwd grid points, form the cube with that */
/* point at its base, and determine the bounding box of the output values */
- /* that could intersect that cube. */
- /* As a start for creating rev.nnrevp[], flag which bwd verticies are */
- /* covered by the fwd grid output range. */
+ /* that could intersect that fwd cube. Add that fwd index to the lists of */
+ /* of all bwd cells that the bounding box intersects. */
+ /* As a start for creating surface bxcell list, flag which bwd verticies */
+ /* are covered by the fwd grid output range. */
+
+ /* Pre-marking device edge rev cells creates many more initial cells, */
+ /* but avoids having to discover them with multiple passes ? */
for (gp = s->g.a, i = 0; i < gno; gp += s->g.pss, i++) {
datao min, max;
int imin[MXRO], imax[MXRO], gc[MXRO];
+ int edge = 0; /* This fwd cell contains a device edge */
int uil; /* One is under the ink limit */
+ int oil; /* One is over the ink limit */
//printf("~1 i = %d/%d\n",i,gno);
/* Skip grid points on the upper edge of the grid, since there */
/* is no further grid point to form a cube range with. */
for (e = 0; e < di; e++) {
- if(G_FL(gp, e) == 0) /* At the top edge */
+ int flags = G_FL(gp, e);
+
+ if (flags == 0) /* At the top edge */
break;
+
+ /* If we at the bottom edge, or one away from top edge */
+ if (flags == 4 || flags == 1)
+ edge = 1; /* This fwd cell is on device gamut edge */
}
if (e < di) { /* Top edge - skip this cube */
+//printf("~1 skipping base vertex %d on top edge\n",i);
continue;
}
+//printf("~1 adding to rev[]\n");
+
/* Find the output value bounding box values for this grid cell */
- uil = 0;
+ /* Start with base vertex */
+ uil = oil = 0;
for (f = 0; f < fdi; f++) /* Init output min/max */
min[f] = max[f] = gp[f];
- if (b == NULL || !s->limiten || gp[-1] <= s->limitv)
+ if (!s->limiten || gp[-1] <= s->limitv)
uil = 1;
+ else
+ edge = oil = 1; /* May be stradling ink limit edge */
- /* For all other grid points in the cube */
+ /* Then add all other fwd cube verticies */
for (ee = 1; ee < (1 << di); ee++) {
float *gt = gp + s->g.fhi[ee]; /* Pointer to cube vertex */
- if (b == NULL || !s->limiten || gt[-1] <= s->limitv)
+ if (!s->limiten || gt[-1] <= s->limitv)
uil = 1;
+ else
+ edge = oil = 1;
/* Update bounding box for this grid point */
for (f = 0; f < fdi; f++) {
@@ -5244,26 +8981,28 @@ rspl *s
}
}
- /* Skip any fwd cells that are over the ink limit */
+ /* Skip any fwd cells that have every vertex over the ink limit */
if (!uil) {
+#if defined(REVTABLESTATS) || defined(DEBUG)
nskcells++;
+#endif
continue;
}
- /* Figure out intersection range in reverse grid */
+ /* Figure out intersection range in bwd cell grid */
for (f = 0; f < fdi; f++) {
double t;
int mi;
double gw = s->rev.gw[f];
double gl = s->rev.gl[f];
- t = (min[f] - gl)/gw;
+ t = (min[f] - gl - EPS)/gw;
mi = (int)floor(t); /* Grid coordinate */
if (mi < 0) /* Limit to valid cube base index range */
mi = 0;
else if (mi > rgres_1)
mi = rgres_1;
imin[f] = mi;
- t = (max[f] - gl)/gw;
+ t = (max[f] - gl + EPS)/gw;
mi = (int)floor(t); /* Grid coordinate */
if (mi < 0) /* Limit to valid cube base index range */
mi = 0;
@@ -5272,51 +9011,51 @@ rspl *s
imax[f] = mi;
}
-//printf("Scanning over grid:\n");
+//printf(" Scanning over bwd cell range grid:\n");
//for (f = 0; f < fdi; f++)
-//printf("Min[%d] = %d -> Max[%d] = %d\n",f,imin[f],f,imax[f]);
+//printf(" Min[%d] = %d -> Max[%d] = %d\n",f,imin[f],f,imax[f]);
/* Now create forward index and vector with all the reverse grid cells */
for (f = 0; f < fdi; f++)
gc[f] = imin[f]; /* init coords */
- for (f = 0; f < fdi;) { /* For all of intersect cube */
- int **rpp, *rp;
+ /* Until increment at bottom carries */
+ for (f = 0; f < fdi;) { /* For all of intersect bwd cube */
+ int **rpp;
+ char *vflagp;
- /* Compute pointer to grid cell */
- for (rpp = s->rev.rev, f = 0; f < fdi; f++)
- rpp += gc[f] * s->rev.coi[f];
- rp = *rpp;
+ /* Compute pointer to bwd grid cell and vflag[] */
+ for (rpp = s->rev.rev, vflagp = vflag, f = 0; f < fdi; f++) {
+ int inc = gc[f] * s->rev.coi[f];
+ rpp += inc;
+ vflagp += inc;
+ }
-//printf("Currently at grid:\n");
-//for (f = 0; f < fdi; f++)
-//printf("gc[%d] = %d\n",f,gc[f]);
-
- if (rp == NULL) {
- if ((rp = (int *) rev_malloc(s, 6 * sizeof(int))) == NULL)
- error("rspl malloc failed - rev.grid entry");
- INCSZ(s, 6 * sizeof(int));
- *rpp = rp;
- rp[0] = 6; /* Allocation */
- rp[1] = 4; /* Next free Cell */
- rp[2] = 1; /* Reference count */
- rp[3] = i;
- rp[4] = -1; /* End marker */
- } else {
- int z = rp[1], ll = rp[0];
- if (z >= (ll-1)) { /* Not enough space */
- INCSZ(s, ll * sizeof(int));
- ll *= 2;
- if ((rp = (int *) rev_realloc(s, rp, sizeof(int) * ll)) == NULL)
- error("rspl realloc failed - rev.grid entry");
- *rpp = rp;
- rp[0] = ll;
- }
- rp[z++] = i;
- rp[z] = -1;
- rp[1] = z;
+#undef PRE_LOAD_SURFACE /* [und] Makes it slower ? */
+#ifdef PRE_LOAD_SURFACE /* Pre-load device edge cells */
+ if (edge) {
+ *vflagp = 2; /* This is definitely a gamut surface bwd cell */
+ /* and so nnrev[] needs to be filled */
+ } else
+#endif
+ if (*vflagp == 0) {
+ *vflagp = 1; /* This is possibly not a surface bwd cell, */
+ /* and otherwise is an inside gamut bwd cell */
}
- /* Increment index */
+
+ if (oil)
+ *vflagp |= 0x10; /* Contains over ink limit vertexes */
+
+//printf("seting vflag[%d] to surface done (%x)\n",vflagp-vflag,*vflagp);
+
+//printf(" Currently at grid ix %d, (vflag = %x) adding fwd %d:\n",vflagp-vflag,*vflagp,i);
+//for (f = 0; f < fdi; f++)
+//printf(" gc[%d] = %d\n",f,gc[f]);
+
+ /* Add fwd cells to rev[] list */
+ add2indexlist(s, rpp, i, 0);
+
+ /* Increment index up to and including imax[] */
for (f = 0; f < fdi; f++) {
gc[f]++;
if (gc[f] <= imax[f])
@@ -5324,811 +9063,2107 @@ rspl *s
gc[f] = imin[f];
}
} /* Next reverse grid point in intersecting cube */
+ } /* Next base grid point */
- if (s->rev.fastsetup)
- continue; /* Skip nnrev setup */
+ DBG(("We skipped %d cells that were over the limit\n",nskcells));
+#ifdef CHECK_NNLU
+ if (fdi > 1) {
+ /* Check that every flagged rev[] cell is filled */
+ printf("Checking all %d flagged rev[] cells are filled\n",rgno);
+ for (i = 0; i < rgno; i++) {
+ if ( (vflag[i] & 1) != 0
+ && (s->rev.rev[i] == NULL || s->rev.rev[i][1] == 3)) {
+ printf("Found empty rev[%d] ?:\n",i);
+ printf(" vflag %x\n",vflag[i]);
+ if (s->rev.rev[i] == NULL)
+ printf(" rev = NULL\n");
+ else
+ printf(" rev = length = %d\n",s->rev.rev[i][1]-3);
+ }
+ }
+ }
+#endif /* CHECK_NNLU */
- /* Now also register which grid points are in-gamut and are part of cells */
- /* than have a rev.rev[] list. */
+ /* If doing fast setup, then this is all we need. */
+ if (s->rev.fastsetup) {
- /* Figure out intersection range in reverse nn (construction) vertex grid */
- /* This range may be empty if a grid isn't stradled by the fwd cell output */
- /* range. */
- for (f = 0; f < fdi; f++) {
- double t;
- int mi;
- double gw = s->rev.gw[f];
- double gl = s->rev.gl[f];
- t = (min[f] - gl)/gw;
- mi = (int)ceil(t); /* Grid coordinate */
- if (mi < 0) /* Limit to valid cube base index range */
- mi = 0;
- else if (mi >= argres)
- mi = rgres;
- imin[f] = mi;
- t = (max[f] - gl)/gw;
- mi = (int)floor(t); /* Grid coordinate */
- if (mi < 0) /* Limit to valid cube base index range */
- mi = 0;
- else if (mi >= argres)
- mi = rgres;
- imax[f] = mi;
- if (imax[f] < imin[f])
- break; /* Doesn't straddle any verticies */
+ /* Free up flag array used for construction */
+ if (vflag != NULL) {
+ DECSZ(s, rgno * sizeof(char));
+ free(vflag);
}
- if (f >= fdi) { /* There are seed verticies to mark */
+ s->rev.rev_valid = 1;
+
+ if (fdi > 1 && s->verbose)
+ fprintf(stdout, "%cFast nnrev initialization done\n",cr_char);
+
+ DBG(("init_revaccell fastsetup finished\n"));
+
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ printf("Fastsetup took %f seconds\n",0.001 * (msec_time()-smsec));
+#endif
+
+ return;
+ }
+
+ /* Rough outline of overall nn setup process:
+
+ Fill rev[] array by scanning fwd cells.
+
+ Locating initial surface bwd cells.
+
+ loop:
+ Fill empty surface cells from rev[] list and convert to vertexes.
+
+ (In two phases, first just against primary bx, second with all
+ shadowed bx's:)
+
+ Test all triangles against all vertexes and mark those that are shadowed.
+
+ Remove vertexes from bx if they have been deleted, but leave
+ them in the vertex cache for testing against.
+
+ If any vertexes of a bx land outside it in a bx that is not
+ part of the surface list, add that bx to the surface list and
+ mark it for processing.
+
+ Track which bx cells shadow newly added bx cells,
+ so that new bx cells get tested against all their shadowers,
+ as well as being used to test against their shadowees.
+
+ Locate and preserve all overlapping surface triangles.
+
+ Delete any shadowed vertexes, and remove any empty bxcells.
+
+ Add extra over ink limit vertexes.
+
+ Convert vertexes back to minimum number of fwd cubes.
+
+ */
+
+ calc_ocent(s);
+
+ /* Locate and process the surface bxcells and fill the nnrev array if we */
+ /* are not doing a fast setup. (fastsetup will instead fill the nnrev[] array */
+ /* on demand, by searching the rev[] array.) */
+ DBG(("Identifying surface rev cells\n"));
+
+ /* Allocate the surflist hash index. */
+ /* (Note that we track bxcells in the surface list rather */
+ /* than the hash list, in this context.) */
+ create_surfhash(s);
+
+ /* Locate surface reverse cells */
+ DC_INIT(gg);
+ for (i = 0; i < rgno; i++) {
+
+ if ((vflag[i] & 0xf) == 1) { /* if filled rev[] cell but not surface */
+ char *vflagp;
-//printf("~1 marking prime seed vertex %d\n",i);
+ /* Check face neighbors */
+ int cc[MXDO]; /* Neigbor offset counter */
- /* Mark an initial seed point nnrev vertex, and */
- /* create a surface point propogation record for it */
+ /* Check if any of the face neigbors of this bwd cell are empty. */
+ /* If so, mark it as a surface cell. */
+ /* [This won't detect all surface nncells, but will hit most of them */
+ /* without including too many false ones. The vertex filter code */
+ /* should discover any surface nncells that are missed.] */
for (f = 0; f < fdi; f++)
- gc[f] = imin[f]; /* init coords */
+ cc[f] = gg[f];
+ vflagp = vflag + i;
- for (f = 0; f < fdi;) { /* For all of intersect cube */
- int **rpp, *rp;
- char *fpp;
-
- /* Compute pointer to grid cell */
- for (rpp = s->rev.nnrev, fpp = vflag, f = 0; f < fdi; f++) {
- int inc = gc[f] * s->rev.coi[f];
- rpp += inc;
- fpp += inc;
- }
- rp = *rpp;
+ for (ff = 0; ff < (fdi << 1); ff++) {
+ f = ff >> 1;
- *fpp = 3; /* Initial seed point */
-
- /* Increment index */
- for (f = 0; f < fdi; f++) {
- gc[f]++;
- if (gc[f] <= imax[f])
- break; /* No carry */
- gc[f] = imin[f];
+ cc[f] += (ff & 1) ? 1 : -1;
+ vflagp += (ff & 1) ? s->rev.coi[f] : -s->rev.coi[f];
+
+
+ /* Out of bounds or empty */
+ if (cc[f] < 0 || cc[f] >= rgres || ((*vflagp & 0xf) == 0)) {
+ vflag[i] = (vflag[i] & ~0xf) | 2; /* Convert this one to empty surface cell */
+//printf("seting vflag[%d] to surface cell (%x)\n",i,vflag[i]);
+
+ /* Add a bxcell to surf hash. Initial status = bx_uninit */
+ if ((bx = get_surface_bxcell(s, i)) == NULL) {
+ /* Since it's a surface point, the seeding point is itself (NULL). */
+ bx = new_bxcell(s, i, gg, NULL, 0.0, NULL);
+ add_bxcell_hash(s, bx);
+
+ /* Add to surface linked list */
+ bx->slist = s->rev.surflist;
+ s->rev.surflist = bx;
+//printf("~1 adding nnrev[%d] to surface list\n",bx->ix);
+ }
+ break;
}
+
+ cc[f] -= (ff & 1) ? 1 : -1;
+ vflagp -= (ff & 1) ? s->rev.coi[f] : -s->rev.coi[f];
+ }
+ }
+#ifdef PRE_LOAD_SURFACE
+ else if ((vflag[i] & 0xf) == 2) { /* Pre-marked surface rev cell */
+
+ /* Add a bxcell to surf hash. Initial status = bx_uninit */
+ if ((bx = get_surface_bxcell(s, i)) == NULL) {
+ /* Since it's a surface point, the seeding point is itself (NULL). */
+ bx = new_bxcell(s, i, gg, NULL, 0.0, NULL);
+ add_bxcell_hash(s, bx);
+
+ /* Add to surface linked list */
+ bx->slist = s->rev.surflist;
+ s->rev.surflist = bx;
+//printf("~1 adding pre-marked nnrev[%d] to surface list\n",bx->ix);
}
}
- } /* Next base grid point */
+#endif /* PRE_LOAD_SURFACE */
- DBG(("We skipped %d cells that were over the limit\n",nskcells));
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ if (vflag[i] & 2)
+ surfcells++;
+ else if ((vflag[i] & 0xf) != 0)
+ ingamutcells++;
+ else
+ emptycells++;
- /* Setup the nnrev array if we are not doing a fast setup. */
- /* (fastsetup will instead fill the nnrev array on demand, */
- /* using an exaustive search.) */
- if (!s->rev.fastsetup) {
+ if (s->rev.rev[i] != NULL) {
+ revcells++;
+ revcelldepth += s->rev.rev[i][1]-3;
+ }
+#endif
+ DC_INC(gg);
+ }
- /* The next step is to use all the prime seed grid points to set and propogate */
- /* the index of the closest fwd vertex through the revnn[] array. */
- /* (This doesn't work perfectly. Sometimes a vertex is not linked to it's closest */
- /* prime. I'm not sure if this is due to a bug here, or is a quirk of geometry */
- /* that a prime that is closest to a vertex isn't closest for any of its neighbors.) */
- DBG(("filling in rev.nnrev[] grid\n"));
+ if (di < 2)
+ {
+ /* Create surface fwd cell list */
+ DBG(("create surface fwd cell lists\n"));
- /* For all the primary seed points */
- DC_INIT(gg);
- for (i = 0; i < rgno; i++) {
- int **rpp;
- primevx *prime= NULL; /* prime cell information structure */
+ /* For each rev[] containing fwd cells, */
+ /* copy the cells to the corresponding surface bxcel cell */
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int *crp, *rp;
+
+ if ((crp = s->rev.rev[bx->ix]) == NULL)
+ error("Surface list bxcell ix %d has no vertexes",bx->ix);
- if (vflag[i] != 3) { /* Not a prime seed point */
- goto next_seed_point;
+ /* For each fwd cell in surface rev[] */
+ for (rp = crp+3; *rp != -1; rp++) {
+ add2indexlist(s, &bx->sl, *rp, 0);
}
+ }
+
+ } else {
+
+#ifdef REVVRML
+ /* Plot the initial surface bxcells & their fwd cells. */
+ /* Rev cells? Fwd cells? Fwd cell base indexs? */
+ if (0) plot_bxfwcells(s, 0, 1, 0);
+#endif /* REVVRML */
+
+ /* per reverse cell vertex cache */
+ create_vtxrec_list(s, &vc);
+
+ /* per reverse cell surface triangle cache */
+ create_trirec(s, &tc, 0);
+
+ /* small per reverse cell surface triangle cache */
+ create_trirec(s, &stc, 1);
+
+ /* create associated sub-simplex (triangle) lookup table */
+ init_assdir(s, &tridir, 2);
+
+ /* create associated sub-simplex (edge) lookup table */
+ init_assdir(s, &edgdir, 1);
+
+ /* Process surface bxcells */
+ /* (Maintain current list of vtxrec's for all vertexes) */
- rpp = s->rev.nnrev + i;
+ /* Setup temporary matrix */
+ for (f = 0; f < 2; f++)
+ ta[f] = TA[f];
+
+ /* - - - - - - - - - - - - - - */
+ /* fill, thin and add, until */
+ /* there is no more work to do. */
+ for (;;) {
+ int phase;
+ int morevtxadded = 0;
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ unsigned long lmsec = msec_time();
+ int thcount = 0, rethcount = 0;
+
+// printf("At top of gamut surface loop\n");
+#endif
-//printf("~1 potential rev.nnrev[] prime seed %d, about to scan neibors\n",i);
- /* For all the neigbors of this seed */
- DC_INIT(cc);
- while (!DC_DONE(cc)) {
- propvx *prop; /* neighor cell propogation structure */
- int nix = 0; /* Neighbor cell index */
- char *fpp = vflag;
- int **nrpp = s->rev.nnrev;
- double dsq;
+ /* For each surface bxcell, convert the corresponding */
+ /* rev[] fwd cubes into vertices. */
+ /* (Musk keep bxcells even if none of their verticies */
+ /* are physically in them, so that those verticies get thinned. */
+ /* could only remove them if vertex was not in any surface cell ?) */
+ for (pbx = &s->rev.surflist, bx = *pbx; bx != NULL; bx = nbx) {
+ int *crp, *rp, *nrp;
+ vtxrec *vx;
+
+ nbx = bx->slist;
- for (f = 0; f < fdi; f++) {
- nn[f] = gg[f] + cc[f];
- if (nn[f] < 0 || nn[f] >= argres)
- break; /* Out of bounds */
- nix += nn[f] * s->rev.coi[f];
+ if (bx->status != bx_uninit) {
+ pbx = &bx->slist;
+ continue;
}
- fpp = vflag + nix;
- /* If neighbor out of bounds, or is a prime seed point, skip it */
- if (f < fdi || *fpp == 3) {
- goto next_neighbor;
- }
+ if ((crp = s->rev.rev[bx->ix]) == NULL)
+ error("Surface list bxcell ix %d has no vertexes",bx->ix);
+
+//printf("Initializing bxcell %d with vertexes\n",bx->ix);
+ /* For each fwd cell in surface rev[] */
+ for (rp = crp+3; *rp != -1; rp++) {
+
+//adding cube %d to bx %d\n",*rp, bx->ix);
+ /* For each vertex of cube */
+ for (ee = 0; ee < (1<<di); ee++) {
+ int vix = *rp + s->g.hi[ee];
+ float *fcb = s->g.a + vix * s->g.pss; /* Pointer to base float of fwd cell */
+ vtxrec *vx;
+
+//printf("~1 adding cube %d vtx %d to bx %d\n",*rp, vix, bx->ix);
-//printf("~1 identified prime seed %d with neighbor %d\n",i,nix);
- /* We now know that this prime seed will propogate, */
- /* so get/create the temporary information record for it */
- if (prime == NULL) {
+ /* Don't add over ink limit vertexes */
+ /* (we'll re-add them in later) */
+ if (s->limiten && fcb[-1] > s->limitv) {
+//printf("Skipping vtx %d because over ink limit\n",vix);
+ continue;
+ }
+
+ if ((vx = get_vtxrec(&vc, vix)) != NULL) {
+ if (vx->rix == bx->ix) {
+//printf("Already have vertex %d in bx %d\n",vx->ix,vx->rix);
+ }
- /* If this prime seed hasn't be setup before */
- if (*rpp != NULL) {
- prime = *((primevx **)rpp);
- } else {
- /* Allocate a primevx if there isn't one */
- if ((prime = (primevx *) calloc(1, sizeof(primevx))) == NULL)
- error("rspl malloc failed - rev.nnrev prime info structs");
- *((primevx **)rpp) = prime;
- prime->ix = i;
- for (f = 0; f < fdi; f++)
- prime->gc[f] = gg[f];
-//if (fdi > 1) printf("~1 setting prime %d, gc = %d, %d, %d\n", i, prime->gc[0], prime->gc[1], prime->gc[2]);
+ /* Skip vertexes that we've already added to this bxcell */
+ if (vx->tix == bx->ix) {
+//printf("Skipping vtx %d because alread in bx %d\n",vix,bx->ix);
+ continue;
+ }
+ } else {
+ /* Create new vertex */
+ vx = new_vtxrec(s, &vc, vix);
+ vx->tix = bx->ix; /* Added to this bx */
+//printf("Create vtx %d for bx %d (actually in bx %d)\n",vix,bx->ix,vx->rix);
+ }
+
+ /* Add vertex to bxcell sl list */
+ add2indexlist(s, &bx->sl, vix, 0);
+
+ if (vx->rix == bx->ix) {
+//printf("Added vertex %d is in this bx %d\n",vx->ix,vx->rix);
+ } else {
+//printf("Added vertex %d is in different bx %d to this one %d\n",vx->ix,vx->rix,bx->ix);
+ }
}
}
+ /* Expand a bxcell's shadow testing group values based on it's vertex list */
+ /* so that shadow testing works correctly for vertexes that don't */
+ /* actually lie within the bxcell. (Note that in fact the triangle */
+ /* testing creates triangles that are mode of vertexes that may not */
+ /* be in this bx's list, so the shadow size doesn't accturatly reprsent */
+ /* the possible shadow area. It's not clear what consequences this has, */
+ /* if any. If we extanded the group to cover this, we would need to have ) */
+ /* two groups, a shadower group including those vertexes, and a shadowee */
+ /* goup for just those vertexes that are part of the bx. */
+ extend_bxcell_shadow_group(s, &vc, bx);
+ bx->status = bx_filled;
+ pbx = &bx->slist;
+ morevtxadded = 1;
+ }
+
+ DBG(("thinning surface vertex lists and converting to cells\n"));
- /* Pointer to nnrev vertex neighbor point */
- nrpp = s->rev.nnrev + nix;
+ /* (Sorting bxcells doesn't seem to make any performace difference.) */
- /* Compute the distance squared from this prime seed to this neighbor */
- for (dsq = 0.0, f = 0; f < fdi; f++) {
- double tt = (gg[f] - nn[f]) * s->rev.gw[f];
- dsq += tt * tt;
- }
+ for (phase = 0; phase < 2; phase++) {
+
+//printf("Phase %d\n",phase);
+
+ /* For each surface bxcell, form triangles from vertexes */
+ /* and mark as shadowed and other vertexes that are in the */
+ /* triangles shadow. */
+ /* rev[] fwd cubes into vertices. */
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int sdi = 2; /* sub-simplexes are triangles */
+ double clb[MXRO+1]; /* Line RHS implicit equation vector [fdi+1] */
+ int *crp, *rp, *nrp;
+ vtxrec *vx, *nvx;
+ int aftercount; /* vertex count after thinning */
- /* Get or allocate a prop structure for it */
- if (*nrpp != NULL) {
- prop = *((propvx **)nrpp);
- if ((dsq + 1e-6) < prop->dsq) { /* This prime is closer than previous */
- prop->cix = i; /* The index of the closest prime */
- prop->dsq = dsq; /* Distance squared to closest prime */
+ if (bx->status != bx_filled && bx->status != bx_rethinnd) {
+//printf("~1 skipping bx %d because status = %d\n",bx->ix,bx->status);
+ continue;
}
- } else {
- if ((prop = (propvx *) calloc(1, sizeof(propvx))) == NULL)
- error("rspl malloc failed - rev.nnrev propogation structs");
- *((propvx **)nrpp) = prop;
- prop->ix = nix;
- for (f = 0; f < fdi; f++)
- prop->gc[f] = nn[f]; /* This neighbors coord */
- prop->cix = i;
- prop->dsq = dsq;
- prop->pass = pass;
- prop->next = nlist; /* Add new seed to list of next seeds */
- nlist = prop;
- *fpp = 1;
+//printf("~1 checking bx %d\n",bx->ix);
- }
- next_neighbor:;
- DC_INC(cc);
- }
+ /* Only do first pass through primary alone if never thinned before */
+ if (phase == 0 && bx->status == bx_rethinnd) {
+ continue;
+ }
- next_seed_point:;
- DC_INC(gg);
- }
+ /* If this bxcell is empty (because all it's vertexes are shadowed ?) */
+ if (bx->sl == NULL || bx->sl[1] == 3) {
+//printf("~1 skipping nnrev[%d] because it's empty\n",bx->ix);
+ continue;
+ }
+//printf("Thinning bxcell %d\n",bx->ix);
+ /* Create nnrev[] shadowing linked list. nnrev[] cells who's shadow in */
+ /* the direction of rev.ocent[] touches another nnrev[], add that nnrev[] */
+ /* to their shadow list. This allows us to filter vertexes in other */
+ /* nnrev[] cells from triangles above them */
+ bx->wlist = NULL;
+
+ /* Only go through all shadowed bxcells once primary has been */
+ /* thinned alone */
+ if (phase == 1) {
+
+ /* Use just extra list for re-thinning, for 10% speed advantage. */
+ if (bx->status == bx_rethinnd && xlist != NULL) {
+//printf("Adding shadows to bxcell %d from xlist\n",bx->ix);
+ for (nbx = xlist; nbx != NULL; nbx = nbx->xlist) {
+
+ if (nbx->status == bx_uninit) /* Newly added cells (shouldn't happen) */
+ break;
-//printf("~1 about to propogate secondary seeds\n");
- /* Now we propogate the secondary seed points until there are no more left */
- while(nlist != NULL) {
- propvx *next;
- propvx *tlp;
+ if (nbx == bx)
+ continue;
+
+ /* If any of bx is further from nbx and their bounding */
+ /* cylinders overlap in perspective from rev.ocenter, */
+ /* assume nbx is a shadow */
+ if (shadow_group_group(s, s->rev.ocent, bx->g.bcent, bx->cc, bx->dw,
+ nbx->g.bcent, nbx->cc, nbx->dw)) {
+ nbx->wlist = bx->wlist;
+ bx->wlist = nbx;
+//printf("~1 adding shadow nnrev[%d] from xlist\n",nbx->ix);
+ }
+ }
+ } else {
- if ((pass += 2) < 0)
- error("Assert rev: excessive propogation passes");
-//printf("~1 about to do a round of propogation pass %d\n",(pass+2)/2);
+//printf("Adding shadows to bxcell %d from surflist\n",bx->ix);
+ for (nbx = s->rev.surflist; nbx != NULL; nbx = nbx->slist) {
- /* Mark all seed points on the current list with pass-1 */
- for (tlp = nlist; tlp != NULL; tlp = tlp->next) {
- *(vflag + tlp->ix) = 2;
- tlp->pass = pass-1;
- }
+//printf("Considering bx %d for shadow list\n",nbx->ix);
+ if (nbx->status == bx_uninit) /* Newly added cells (shouldn't happen) */
+ break;
- /* Go through each secondary seed in the active list, propogating them */
- for (alist = nlist, nlist = NULL; alist != NULL; alist = next) {
- int **rpp;
- primevx *prime= NULL; /* prime cell information structure */
+ if (nbx == bx)
+ continue;
+
+ /* If any of bx is further from nbx and their bounding */
+ /* cylinders overlap in perspective from rev.ocenter, */
+ /* assume nbx is a shadow */
+ if (shadow_group_group(s, s->rev.ocent, bx->g.bcent, bx->cc, bx->dw,
+ nbx->g.bcent, nbx->cc, nbx->dw))
+ {
+//printf("Added bx %d for shadow list, prim bx %d\n",nbx->ix,bx->ix);
+ nbx->wlist = bx->wlist;
+ bx->wlist = nbx;
+ }
+ }
+ }
+ } /* if phase == 1 */
- next = alist->next; /* Next unless we re-insert one */
-
- /* Grab this seed points coodinate and index */
- for (i = f = 0; f < fdi; f++) {
- gg[f] = alist->gc[f];
- i += gg[f] * s->rev.coi[f];
- }
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ if (bx->status == bx_rethinnd)
+ rethcount++;
+ else
+ thcount++;
+#endif
-//printf("\n~1 propogating from seed %d\n",i);
- /* rpp = s->rev.nnrev + i; */
-
- /* Grab the corresponding prime seed information record */
- prime = *((primevx **)(s->rev.nnrev + alist->cix));
-
- /* For all the neigbors of this seed */
- DC_INIT(cc);
- while (!DC_DONE(cc)) {
- propvx *prop; /* neighor cell propogation structure */
- int nix; /* Neighbor cell index */
- char *fpp = vflag;
- int **nrpp = s->rev.nnrev;
- double dsq;
-
- for (nix = f = 0; f < fdi; f++) {
- nn[f] = gg[f] + cc[f];
- if (nn[f] < 0 || nn[f] >= argres)
- break; /* Out of bounds */
- nix += nn[f] * s->rev.coi[f];
+ /* Abort doing this cell until all its shadowees are filled */
+ /* (Shouldn't happen ?) */
+ if (nbx != NULL) {
+//printf("Skipping thinning of bx %d because newly added bx %d is in surfce list\n",bx->ix,nbx->ix);
+ continue;
}
- fpp = vflag + nix;
-//printf("~1 neighbor ix %d, flag %d\n",nix,*fpp);
-
- /* If neighbor out of bounds, current vertex or prime, skip it */
- if (f < fdi || i == nix || *fpp >= 3) {
-//printf("~1 skipping neighbour %d\n",nix);
- goto next_neighbor2;
+
+ /* Be able to detect triangles already tested */
+ /* from this shadowing bxcell. */
+ clear_trirec(s, &tc);
+
+ /* Put just primary and shadows on vx->tlist */
+ vc.vtxlist = NULL;
+ vc.nilist = 0;
+
+ /* Add all the secondary bxcell vertexes to the vtxlist */
+ for (nbx = bx->wlist; nbx != NULL; nbx = nbx->wlist) {
+//printf("Adding bx %d verticies\n",nbx->ix);
+ for (rp = nbx->sl+3; *rp != -1; rp++) {
+
+ if ((vx = get_vtxrec(&vc, *rp)) == NULL)
+ error("Failed to find vertex %s in cache",*rp);
+
+//printf("Checking ix %d from bx %d\n",vx->ix,nbx->ix);
+ /* Check vertex falls within shadow of main bx */
+ /* (just checking non-deleted vertexes (triangles) */
+ /* improves speed by 20%, but we end up with stray fwd cells */
+ /* and some holes, because crossed triangles vertexes get */
+ /* marked deleted ??) */
+ if (
+// vx->status == vtx_norm &&
+ shadow_group_vertex(s, s->rev.ocent, bx->g.bcent, bx->cc, bx->dw,
+ vx->v)) {
+ add_vtxrec_list(&vc, vx, 0); /* Add if not deleted */
+//printf(" Added ix %d from bx %d\n",vx->ix,nbx->ix);
+ }
+//else
+//printf(" Not added ix %d from bx %d because no within prim bx %d\n",vx->ix,nbx->ix,bx->ix);
+ }
}
- /* Pointer to nnrev vertex neighbor point */
- nrpp = s->rev.nnrev + nix;
-
- /* Compute the distance squared from the prime seed to this neighbor */
- for (dsq = 0.0, f = 0; f < fdi; f++) {
- double tt = (prime->gc[f] - nn[f]) * s->rev.gw[f];
- dsq += tt * tt;
- }
+ /* Add all the primary bxcell verticies to the list, and */
+ /* mark them (override shadow mark) */
+//printf("Adding bx %d verticies\n",bx->ix);
+ for (rp = bx->sl+3; *rp != -1; rp++) {
+ if ((vx = get_vtxrec(&vc, *rp)) == NULL)
+ error("Failed to find vertex %s in cache",*rp);
- /* Get or allocate a prop structure for it */
- if (*nrpp != NULL) {
- prop = *((propvx **)nrpp);
-//if (prop->ix != nix) error ("Assert: prop index %d doesn't match index %d",prop->ix, nix);
-
- if ((dsq + 1e-6) < prop->dsq) { /* This prime is closer than previous */
-//printf("~1 updating %d to prime %d, dsq = %f from %f\n",nix, prime->ix, dsq, prop->dsq);
- prop->cix = prime->ix; /* The index of the new closest prime */
- prop->dsq = dsq; /* Distance squared to closest prime */
- /* If this is a vertex from previous pass that has changed, */
- /* and it's not ahead of us in the current list, */
- /* put it next on the current list. */
- if (*fpp == 2 && prop->pass != (pass-1)) {
-//printf("~1 re-shedule %d (%d) for next propogate\n",nix,prop->ix);
-//if (next == NULL)
-//printf("Before insert, next = NULL\n");
-//else
-//printf("Before insert, next = %d\n",next->ix);
- prop->pass = pass-1; /* Re-shedule once only */
- prop->next = next;
- next = prop;
- }
+ if (vx->status == vtx_norm &&
+ shadow_group_vertex(s, s->rev.ocent, bx->g.bcent, bx->cc, bx->dw, vx->v)) {
+ add_vtxrec_list(&vc, vx, 1); /* Add if not hidden/deleted */
}
- } else {
- if ((prop = (propvx *) calloc(1, sizeof(propvx))) == NULL)
- error("rspl malloc failed - rev.nnrev propogation structs");
- *((propvx **)nrpp) = prop;
- prop->ix = nix;
- for (f = 0; f < fdi; f++)
- prop->gc[f] = nn[f]; /* This neighbors coord */
- prop->cix = prime->ix;
- prop->dsq = dsq;
-//printf("~1 propogating to new, %d, dsq = %f, prime %d\n",nix, dsq, prime->ix);
- prop->pass = pass;
- prop->next = nlist; /* Add new seed to list of next seeds */
- nlist = prop;
- *fpp = 1;
}
- next_neighbor2:;
- DC_INC(cc);
- }
- alist->pass = pass;
- }
- }
+ aftercount = vc.nilist;
-#ifdef DEBUG
- DBG(("checking that every vertex is now touched\n"));
- for (i = 0; i < rgno; i++) {
- if (vflag[i] < 2) {
- printf("~1 problem: vertex %d flag = %d\n",i, vflag[i]);
- }
- if (vflag[i] == 2 && *(s->rev.nnrev + i) == NULL) {
- printf("~1 problem: vertex %d flag = %d and struct = NULL\n",i, vflag[i]);
- }
- }
-#endif /* DEBUG */
+ /* sort vertexes by decending distance to center point */
+ /* (and also reset list tflag) */
+ sort_vtxrec_list(s, &vc);
+
+ /* For vertexes of this bxcell and shadowers, */
+ /* in order from largst to smallest distance from center. */
+ for (vx = vc.vtxlist; vx != NULL; vx = vx->tlist) {
+ float *vp; /* Vertex being tested */
+ int fl;
+ assdire *tri; /* Triangle table */
+
+//printf("~1 checking against vtx %d\n",vx->ix);
+
+ /* Only check triangles using verticies of the primary bxcell, */
+ /* not shadow bx's. */
+ if (!vx->prim)
+ continue;
-#ifdef NEVER /* Check that all cells are closest to their primes than any other */
-DC_INIT(gg);
-for (i = 0; i < rgno; i++) { /* For all the verticies */
- if (vflag[i] == 2) {
- propvx *prop = (propvx *) *(s->rev.nnrev + i);
- for (j = 0; j < rgno; j++) { /* For all the primes */
- if (vflag[j] == 3) {
- primevx *prime = (primevx *) *(s->rev.nnrev + j);
- double dsq;
- if (prime == NULL)
- continue;
- for (dsq = 0.0, f = 0; f < fdi; f++) {
- double tt = (prime->gc[f] - prop->gc[f]) * s->rev.gw[f];
- dsq += tt * tt;
- }
- if ((dsq + 1e-6) < prop->dsq) {
- warning("~1 vertex %d prime %d, dsq = %f, is closer to prime %d, dsq %f\n", i,prop->cix, prop->dsq, j, dsq);
- /* See if any of the neighbors have the closer prime */
- DC_INIT(cc); /* For all the neigbors of this seed */
- while (!DC_DONE(cc)) {
- propvx *nprop; /* neighor cell propogation structure */
- int nix; /* Neighbor cell index */
- char *fpp = vflag;
- int **nrpp = s->rev.nnrev;
- double dsq;
-
- for (nix = f = 0; f < fdi; f++) {
- nn[f] = gg[f] + cc[f];
- if (nn[f] < 0 || nn[f] >= argres)
- break; /* Out of bounds */
- nix += nn[f] * s->rev.coi[f];
+//printf("~1 doing vertex %d at %s dist %f\n",vx->ix, debPdv(fdi,vx->v), sqrt(vx->dist));
+
+ vp = s->g.a + vx->ix * s->g.pss; /* This vertex in fwd grid */
+ fl = FLV(vp); /* Edge flags for this vertex */
+
+ tri = tridir + fl;
+//printf("~1 fl %d = 0o%o, no triangles %d\n",fl, fl, tri->no);
+
+ /* For all possible triangles that use this vertex */
+ for (i = 0; i < tridir[fl].no; i++) {
+ int triix[3];
+ vtxrec *trivx[3];
+ double v[MXRI+1][MXRO]; /* Triangle vertex values */
+ double gc[MXRO], cc, dw; /* Triangle shadow group info. */
+ int ntvsh = 0; /* Number of triangle verticies shadowed */
+ double bdist = -1.0;
+
+ /* Get triangle verticy values */
+ for (e = 0; e <= sdi; e++) {
+ triix[e] = vx->ix + tri->ti[i].goffs[e];
+
+ if ((trivx[e] = get_vtxrec(&vc, triix[e])) == NULL)
+ break; /* Vertex doesn't exist in our set */
+
+ if (trivx[e]->status != vtx_norm)
+ ntvsh++;
+
+ if (trivx[e]->dist > bdist)
+ bdist = trivx[e]->dist;
}
- fpp = vflag + nix;
-//printf("~1 neighbor ix %d, flag %d\n",nix,*fpp);
+//printf("~1 tri %d: vtxs %s goffs %s\n",i, debPiv(di,triix), debPiv(sdi+1, tri->ti[i].goffs));
+
+ /* Don't test against triangle unless all vertexes */
+ /* are in current surface, and whole triangle is visible. */
+ if (e <= sdi || ntvsh >= 3)
+ continue;
+
+ /* If triangle has been done before for this bxcell, skip it. */
+ if (check_trirec(s, &tc, triix))
+ continue;
- /* If neighbor out of bounds, current vertex or prime, skip it */
- if (f < fdi || i == nix || *fpp != 2) {
-//printf("~1 skipping neighbour %d\n",nix);
- goto next_neighbor3;
+ for (e = 0; e <= sdi; e++) {
+ for (f = 0; f < fdi; f++)
+ v[e][f] = trivx[e]->v[f];
}
- /* Pointer to nnrev vertex neighbor point */
- nrpp = s->rev.nnrev + nix;
- if ((nprop = *((propvx **)nrpp)) != NULL) {
-//printf("~1 neighbor %d %d %d has prime %d dsq %f\n",cc[0],cc[1],cc[2],nprop->cix,nprop->dsq);
- if (nprop->cix == j) {
-//warning("~1 but neighbor has this prime point!\n");
+ /* Compute shadow group params of triangle for quick vertex test */
+ comp_shadow_group(s, s->rev.ocent, gc, &cc, &dw, NULL, v, sdi+1);
+
+ /* For all vertexes */
+ for (nvx = vc.vtxlist; nvx != NULL; nvx = nvx->tlist) {
+ double pv[MXRO]; /* Vertex being tested */
+ double de[MXRO]; /* Line delta */
+ double tb[MXRI]; /* Solution point in input space */
+ double xv[MXRO]; /* Solution point in output space */
+ int g, sorv, wsrv; /* Solved & within simplex return value */
+ double dist; /* distance to line origin */
+ double dot; /* dot product of solution to line */
+ int shdwd; /* whether vertex is shadowed */
+
+ /* If vertex is above triangle, it can't be shadowed */
+ if (nvx->dist > bdist)
+ continue;
+
+ /* If this other vertex has already been deleted, skip it */
+ if (nvx->status != vtx_norm)
+ continue;
+
+ /* If this other vertex is part of the triangle, skip it */
+ if (nvx->ix == triix[0]
+ || nvx->ix == triix[1]
+ || nvx->ix == triix[2]) {
+ continue;
+ }
+
+//printf("~1 checking vertex %d against tri %s\n",nvx->ix,debPiv(3,triix));
+
+ /* Do quick check against triangle */
+ if (!shadow_group_vertex(s,
+ s->rev.ocent, gc, cc, dw, nvx->v)) {
+//printf("~1 shadow group check shows no intersection\n");
+ continue;
+ }
+
+//printf("~1 checking vertex %d at %s dist %f\n",nvx->ix, debPdv(fdi,nvx->v), sqrt(nvx->dist));
+
+ /* Compute intersection: */
+ shdwd = wsrv = 0;
+
+ /* Compute line delta */
+ vp = s->g.a + nvx->ix * s->g.pss;
+ for (f = 0; f < fdi; f++) {
+ pv[f] = vp[f];
+ de[f] = pv[f] - s->rev.ocent[f];
+ }
+
+ /* Setup line cla and clb */
+ init_line_eq_imp(s, NULL, &cla, clb, s->rev.ocent, de, 0);
+
+ /* Solve line/triangle intersection using same */
+ /* method as vnearest_clip_solve(). */
+
+ /* LHS: ta[sdi][sdi] = cla[sdi][fdi] * vv[fdi][sdi] */
+ /* RHS: tb[sdi] = clb[sdi] - cla[sdi][fdi] * vv_di[fdi] */
+ for (f = 0; f < sdi; f++) {
+ double tt;
+ for (e = 0; e < sdi; e++) {
+ for (tt = 0.0, g = 0; g < fdi; g++)
+ tt += cla[f][g] * (v[e][g] - v[e+1][g]);
+ ta[f][e] = tt;
+ }
+ for (tt = 0.0, g = 0; g < fdi; g++)
+ tt += cla[f][g] * v[sdi][g];
+ tb[f] = clb[f] - tt;
+ }
+
+ /* Compute the solution */
+ /* (Solve the simultaneous linear equations A.X = B) */
+// sorv = !solve_se(ta, tb, sdi);
+ sorv = !solve_se_2x2(ta, tb); /* Saves a few % only */
+
+ /* If it was solved */
+ if (sorv) {
+
+ /* Check that the solution is within the simplex & ink limit */
+ if ((wsrv = simple_within_simplex(v, tb, sdi)) != 0) {
+
+ /* Compute the output space solution point */
+ for (f = 0; f < fdi; f++) {
+ double tt = 0.0;
+ for (e = 0; e < sdi; e++)
+ tt += (v[e][f] - v[e+1][f]) * tb[e];
+ xv[f] = tt + v[sdi][f];
+ }
+
+ /* Compute distance to gamut center squared, */
+ /* as well as the dot product */
+ for (dot = dist = 0.0, f = 0; f < fdi ; f++) {
+ double tt = (xv[f] - s->rev.ocent[f]);
+ dist += tt * tt;
+ dot += de[f] * tt;
+ }
+//printf("~1 intersection at %s dist %f\n", debPdv(fdi,xv), sqrt(dist));
+
+ /* If intersection distance is greater than vertex distance, */
+ /* delete the vertex */
+ if (dot > 0.0 && dist > (nvx->dist + EPS)) {
+ shdwd = 1;
+ nvx->status = vtx_sha; /* Shadowed */
+ aftercount--;
+//printf("~1 deleting vx %d\n",nvx->ix);
+ }
+ }
+ }
+//if (!sorv) printf("~1 solve failed\n");
+//if (sorv && !wsrv) printf("~1 %d not within simplex, tb = %s\n",nvx->ix, debPdv(sdi,tb));
+//if (sorv && wsrv && shdwd) printf("~1 tri %s deleting vertex %d\n",debPiv(3,triix), nvx->ix);
+
+#ifdef REVVRML
+ /* Plot vertex & triangle check setup & solution */
+ /* + the primary and shadow bxcells. */
+ /* Plot prim & shadow bxcell cells ? Wait for user press ? */
+ if (0 && phase && shdwd) plot_tri_check(s, 1, 1,
+ bx, vx->ix, i, triix, nvx->ix, sorv, wsrv, shdwd, v, de, pv, xv);
+#endif /* REVVRML */
+
+ } /* Next other vertex */
+ } /* Next triangle */
+ } /* Next main vertex */
+
+ if (phase == 1)
+ bx->status = bx_thinned;
+//printf("Thinned vertexes in bx %d from %d to %d (%d)\n",bx->ix, vc.nilist,aftercount, vc.nilist-aftercount);
+ } /* Next surface bx cell */
+ /* Done with lists */
+ vc.vtxlist = NULL;
+ vc.nilist = 0;
+ xlist = NULL;
+
+ DBG(("deleting verticies in all bxcells\n"));
+
+ /* The thinning may have deleted verticies from bxcell's that */
+ /* were not involved in the thinning, so go though all bxcells */
+ /* to do deletions. Look also for any needed additional surface bxcells. */
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int beforecount, aftercount;
+ vtxrec *nvx;
+ int *crp, *rp, *nrp;
+
+ if (bx->status == bx_uninit)
+ continue;
+
+#ifdef REVVRML
+ bx->debug = 0; /* Not an addition */
+#endif
+
+ beforecount = bx->sl[1]-3;
+
+#undef DELETE_SHAD /* [und] try deleting shadowed vertexes with no un-shadowed neighbors. */
+ /* Seems to actually slow things down though ? */
+
+ /* Delete all the marked vertexes from bxcell list */
+ for (nrp = rp = bx->sl+3; *rp != -1; rp++) {
+ vtxrec *vx;
+#ifdef DELETE_SHAD
+ int nshad = 0, nnshad = 0;
+#endif
+ if ((vx = get_vtxrec(&vc, *rp)) == NULL)
+ continue; /* Already deleted */
+
+#ifdef REVVRML
+ vx->addvtx = 0;
+#endif
+
+#ifdef DELETE_SHAD
+ /* Check all of its neighbor vertexes, to see if */
+ /* it's safe to actually delete them. */
+ if (vx->status >= vtx_sha) { /* vertex to delete ? */
+ float *vp;
+ int fl;
+ assdire *edg; /* Edge table */
+
+//printf("Checking vx %d neighbors\n",vx->ix);
+ vp = s->g.a + vx->ix * s->g.pss; /* This vertex in fwd grid */
+ fl = FLV(vp); /* Edge flags for this vertex */
+ edg = edgdir + fl;
+
+ /* For all possible edges that use this vertex */
+ for (i = 0; i < edgdir[fl].no; i++) {
+ int eix;
+
+ /* Edge vertex index number of other vertex */
+ if (edg->ti[i].goffs[0] != 0)
+ eix = vx->ix + edg->ti[i].goffs[0];
+ else
+ eix = vx->ix + edg->ti[i].goffs[1];
+
+ if ((nvx = get_vtxrec(&vc, eix)) != NULL) {
+//printf("vx %d neighbor vx %d status %d\n",vx->ix,nvx->ix,nvx->status);
+ if (nvx->status >= vtx_sha) {
+ nshad++;
+ } else {
+ nnshad++;
+ }
}
}
- next_neighbor3:;
- DC_INC(cc);
}
-// prop->cix = j; /* Fix it and see what happens */
-// prop->dsq = dsq;
- }
- }
+//printf("vx %d nshad %d nnshad %d\n",vx->ix);
+#endif /* DELETE_SHAD */
+
+ /* Keep un-shadowed vertexes and */
+ /* shadowes ones that have non-shadows neigbors */
+ if (vx->status == vtx_norm
+#ifdef DELETE_SHAD
+ || vx->status >= vtx_sha && nnshad != 0
+#endif
+ ) {
+ *nrp++ = *rp;
+//printf("~1 leaving vtx %d status %d in bxcell %d list\n",vx->ix,vx->status,bx->ix);
+
+ if (phase == 1) {
+#ifndef NEVER /* Do additions */
+ /* If vertex doesn't land in a surface bxcell, */
+ /* create a new surface bxcell for it. */
+ if (vx->status == vtx_norm // ????
+ && (vflag[vx->rix] & 2) == 0) {
+ bxcell *nx;
+
+//if (get_surface_bxcell(s, vx->rix) != NULL)
+//error("new addition bx %d is already surface cell!\n",vx->rix);
+
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ nascells++;
+#endif
+ /* Since it's a surface point, the seeding point is itself (NULL). */
+ nx = new_bxcell(s, vx->rix, vx->ival, NULL, 0.0, NULL);
+ add_bxcell_hash(s, nx);
+ /* Convert to empty surface cell */
+ vflag[nx->ix] = (vflag[nx->ix] & ~0xf) | 2;
+
+ /* Add to surface linked list */
+ nx->slist = s->rev.surflist;
+ s->rev.surflist = nx;
+
+ /* Add to additions list */
+ nx->xlist = xlist;
+ xlist = nx;
+//printf("Added bxcell %d, status %d due to vx %d status %d\n",nx->ix, nx->status,vx->ix,vx->status);
+
+#ifdef REVVRML
+ vx->addvtx = 1; /* Cause of added bxcell */
+ nx->debug = 1; /* Mark added bxcells */
+#endif
+ }
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ /* Keep addvtx flag straight */
+ else if (vx->status == vtx_norm) {
+ bxcell *nx;
+ if ((nx = get_surface_bxcell(s, vx->rix)) != NULL) {
+ if (nx->status == bx_uninit) /* Must be just added */
+ vx->addvtx = 1; /* Cause of added bxcell */
+ }
+ }
+#endif
+ }
+#endif /* Do additions */
+ /* Omit vertex from bx list, and mark it as deleted, */
+ /* and remove it if it has no un-shadowed neighbors */
+ } else {
+ vx->status = vtx_del;
+//printf("~1 marking vtx %d status %d nnshad %d deleted bxcell %d list\n",vx->ix,vx->status,nnshad,bx->ix);
+#ifdef DELETE_SHAD
+ /* Remove it from cache if all its neighbors are */
+ /* shadowed too. */
+ if (nnshad == 0) {
+//printf("~1 deleting vtx %d\n",vx->ix);
+ del_vtxrec_hash(&vc, vx->ix);
+ if (get_vtxrec(&vc, vx->ix) != NULL)
+ error("get_vtxrec suceeded after del_vtxrec_hash!");
+ }
+#else /* !DELETE_SHAD */
+ /* Keep track of deleted verticies that are in this bx, */
+ /* so we can add back in crossing triangle vertexes */
+ add2indexlist(s, &bx->dl, vx->ix, 0);
+#endif /* !DELETE_SHAD */
+ }
+ } /* Next vertex in bx's list */
+ *nrp = -1;
+ bx->sl[1] = nrp - bx->sl;
+
+//aftercount = bx->sl[1]-3;
+//if (beforecount != 0 && aftercount < beforecount) printf("Reduced bx from %d to %d verticies\n",beforecount,aftercount);
+ } /* Next bx */
+ } /* Next phase */
+
+#ifdef REVVRML
+ /* Main summary plot at each thinning round */
+ /* Vtx ix tag ? Deleted vtxs ? Added vtxs ? Preserved vtxs ? oil ? bxcells ? Wait ? */
+ if (0) plot_vtx_surface(s, 0, 0, 1, 0, 0, 0, 1, &vc, edgdir);
+#endif /* REVVRML */
+
+ if (xlist == NULL) {
+ break; /* No added surface cells */
}
- }
- DC_INC(gg);
-}
-#endif /* NEVER */
+ DBG(("reseting shadowers of new bxcells\n"));
+ /* Locate all the bxcells that shadow the added bxcells, */
+ /* and revert status to rethinned. */
+ for (bx = xlist; bx != NULL; bx = bx->xlist) {
+
+#ifdef REVVRML
+ for (nbx = s->rev.surflist; nbx != NULL; nbx = nbx->slist)
+ nbx->debug = 0;
+#endif
- DBG(("about to do convert vertex values to cell lists\n"));
- /* Setup a cache for the fwd cell lists created, so that we can */
- /* avoid the list creation and memory allocation for identical lists */
- nncsize = s->rev.ares * s->rev.ares;
- if ((nnc = (nncache **) calloc(nncsize, sizeof(nncache *))) == NULL)
- error("rspl malloc failed - rev.nnc cache entries");
+ /* Locate the nnrev[] bxcells that shadow this added bxcell */
+ bx->wlist = NULL; /* For debug */
+ for (nbx = s->rev.surflist; nbx != NULL; nbx = nbx->slist) {
- /* Now convert the nnrev secondary vertex points to pointers to fwd cell lists */
- /* Do this in order, so that we don't need the verticies after */
- /* they are converted to cell lists. */
- DC_INIT(gg);
- for (i = 0; i < rgno; i++) {
- int **rpp, *rp;
- propvx *prop = NULL; /* vertex information structure */
- primevx *prime= NULL; /* prime cell information structure */
- int imin[MXRO], imax[MXRO]; /* Prime vertex range for each axis */
- double rmin[MXRO], rmax[MXRO]; /* Float prime vertex value range */
- unsigned int tcount; /* grid touch count for this opperation */
- datao min, max; /* Fwd cell output range */
- int lpix; /* Last prime index seen */
-
-//if (fdi > 1) printf("~1 converting vertex %d\n",i);
-//if (fdi > 1) printf("~1 coord %d %d %d\n",gg[0],gg[1],gg[2]);
-
- rpp = s->rev.nnrev + i;
- if (vflag[i] == 3) { /* Cell base is prime */
- prime = (primevx *) *rpp;
-
- if (prime != NULL) { /* It's a propogating prime */
- /* Add prime to the end of the ptime linked list */
- prime->next = NULL;
- if (plist == NULL) {
- plist = ptail = prime;
- } else {
- ptail->next = prime;
- ptail = prime;
- }
- }
- } else if (vflag[i] == 2) { /* Cell base is secondary */
- prop = (propvx *)*rpp;
- } else { /* Hmm */
- /* This seems to happen if the space explored is not really 3D ? */
- if (s->rev.primsecwarn == 0) {
- warning("rev: bwd vertex %d is not prime or secondary (vflag = %d)"
- "(Check that your measurement data is sane!)",i,vflag[i]);
- s->rev.primsecwarn = 1;
- }
- fill_nncell(s, gg, i); /* Is this valid to do ?? */
- continue;
- }
-
- /* Setup to scan of cube corners, and check that base is within cube grid */
- for (f = 0; f < fdi; f++) {
- if (gg[f] > rgres_1) { /* Vertex outside bwd cell range, */
- if (prop != NULL && prime == NULL) {
- free(prop);
- *rpp = NULL;
+ if (
+#ifdef REVVRML
+ (nbx->status != bx_thinned && nbx->status != bx_filled) // Show all
+#else
+ (nbx->status != bx_thinned)
+#endif
+ || nbx == bx
+ || nbx->sl == NULL
+ || nbx->sl[1] == 3)
+ continue;
+
+ /* If any of nbx is further from bx and their bounding cylinders */
+ /* overlap in perspective from rev.ocenter, assume nbx is a shadower. */
+ if (shadow_group_group(s, s->rev.ocent, nbx->g.bcent, nbx->cc, nbx->dw,
+ bx->g.bcent, bx->cc, bx->dw)) {
+ nbx->status = bx_rethinnd;
+
+#ifdef REVVRML
+ bx->debug = 1; /* rethinned bx */
+ nbx->debug = 2; /* added bx */
+ nbx->wlist = bx->wlist; /* For debug */
+ bx->wlist = nbx;
+#endif
+//printf("~1 marking bxcell %d as un-thinned due to added bxcell %d\n",nbx->ix, bx->ix);
}
-//printf("~1 done vertex %d because its out of cell bounds\n",i);
- goto next_vertex;
}
- imin[f] = 0x7fffffff;
- imax[f] = -1;
- }
- /* For all the vertex points in the nnrev cube starting at this base (i), */
- /* Check if any of them are secondary seed points */
- for (ff = 0; ff < (1 << fdi); ff++) {
- if (vflag[i + s->rev.hoi[ff]] == 2)
- break;
+#ifdef REVVRML
+ /* Plot bxcells touched by added cell */
+ if (0) plot_touched_bxcells(s, bx->ix);
+#endif /* VRML */
}
- /* If not a cell that we want to create a nearest fwd cell list for */
- if (ff >= (1 << fdi)) {
- /* Don't free anything, because we leave a prime in place, */
- /* and it can't be a prop. */
- goto next_vertex;
- }
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ printf(" %d bxcells thinned, %d re-thinned\n",thcount,rethcount);
+ printf("Loop took %f seconds\n",0.001 * (msec_time()-lmsec));
+#endif
+ } /* Loop until done */
- /* For all the vertex points in the nnrev cube starting at this base (i), */
- /* accumulate the range they cover */
- lpix = -1;
- for (f = 0; f < fdi; f++) {
- imin[f] = 0x7fffffff;
- imax[f] = -1;
- }
- for (ff = 0; ff < (1 << fdi); ff++) {
- int ii = i + s->rev.hoi[ff]; /* cube vertex index */
- primevx *tprime= NULL;
-
- /* Grab vertex info and corresponding prime vertex info */
- if (vflag[ii] == 3) { /* Corner is a prime */
- tprime = (primevx *) *(s->rev.nnrev + ii); /* Use itself */
- if (tprime == NULL)
- continue; /* Not a propogated in-gamut vertex */
- } else if (vflag[ii] == 2) {
- propvx *tprop = (propvx *) *(s->rev.nnrev + ii); /* Use propogated prime */
- tprime = (primevx *) *(s->rev.nnrev + tprop->cix);
- } else {
- continue; /* Hmm */
- }
- if (tprime->ix == lpix)
- continue; /* Don't waste time */
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ printf("Thinning took %f seconds\n",0.001 * (msec_time()-smsec));
+#endif
-//if (fdi > 1) printf("~1 corner %d, ix %d, prime %d gc = %d, %d, %d\n", ff, ii, tprime->ix, tprime->gc[0], tprime->gc[1], tprime->gc[2]);
+ /* = = = = = = = = = = = = = = = = = = */
+ DBG(("Preserving overlapping triangles\n"));
+ {
+#ifdef REVTABLESTATS
+ int notverts = 0; /* Number of possible crossed triangles/test verticies */
+ int nopreserved = 0; /* Number of verticies preseved for crossied triangles */
+ unsigned long lmsec = msec_time();
+#endif
+ int sdi = 2; /* sub-simplexes are triangles */
+ int k, jj;
+ vtxrec *vx;
+
+ /* Struct to hold test vertex locations */
+ struct _tvxrec {
+ double v[MXRO];
+ double dist; /* Distance from center point squared */
+ int ix[MXRO+1]; /* Indexes of the triangle verticies */
+ int shad; /* Test result */
+ struct _tvxrec *tlist;
+ }; typedef struct _tvxrec tvxrec;
+ tvxrec *tlist = NULL, *ftlist = NULL, *tvx, *ntvx;
+ int nitlist = 0;
+
+ /* For each surface bxcell, form triangles from vertexes */
+ /* and detect possible crossed triangles */
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int sdi = 2; /* sub-simplexes are triangles */
+ double clb[MXRO+1]; /* Line RHS implicit equation vector [fdi+1] */
+ int *crp, *rp, *nrp;
+ vtxrec *vx, *nvx;
+ int aftercount; /* vertex count after thinning */
+
+ /* Skip cell if empty */
+ if (bx->sl == NULL || bx->sl[1] == 3)
+ continue;
+
+ /* Put the testing triangle verticies on the vtxlist */
+ vc.vtxlist = NULL;
+ vc.nilist = 0;
+
+ /* Be able to detect triangles already tested */
+ /* from this shadowing bxcell. */
+ clear_trirec(s, &tc);
+
+ /* See whether to add cell verticies to the list. */
+ for (rp = bx->sl+3; *rp != -1; rp++) {
+ assdire *tri; /* Triangle table */
+ float *fp;
+ int fl;
+ int added = 0;
+
+ if ((vx = get_vtxrec(&vc, *rp)) == NULL)
+ error("Failed to find vertex %s in cache",*rp);
+
+ if (vx->status != vtx_norm) // ???
+ continue;
- /* Update bounding box for this prime grid point */
- for (f = 0; f < fdi; f++) {
- if (tprime->gc[f] < imin[f])
- imin[f] = tprime->gc[f];
- if (tprime->gc[f] > imax[f])
- imax[f] = tprime->gc[f];
- }
- lpix = tprime->ix;
- }
+ fp = s->g.a + vx->ix * s->g.pss; /* This vertex in fwd grid */
+ fl = FLV(fp); /* Edge flags for this vertex */
+ tri = tridir + fl;
-//if (fdi > 1) printf("~1 prime vertex index range = %d - %d, %d - %d, %d - %d\n", imin[0], imax[0], imin[1], imax[1], imin[2], imax[2]);
+ /* For all +ve triangles that use this vertex */
+ for (k = 0; k < tridir[fl].no; k++) {
+ int triix[MXRI+1];
+ vtxrec *trivx[3];
+ int ntvsh = 0; /* Number of verticies shadowed */
+ int nntvsh = 0; /* Number of verticies not shadowed */
- /* See if a list matching this range is in the cache */
- hashk = 0;
- for (hashk = f = 0; f < fdi; f++)
- hashk = hashk * 97 + imin[f] + 43 * (imax[f] - imin[f]);
- hashk = hashk % nncsize;
-//if (fdi > 1) printf("~1 hashk = %d from %d - %d %d - %d %d - %d\n", hashk, imin[0], imax[0], imin[1], imax[1], imin[2], imax[2]);
+//printf("~1 tri %d: goffs = %s\n", k, debPiv(sdi+1, tri->ti[k].goffs));
- /* See if we can locate an existing list for this range */
- for (ncp = nnc[hashk]; ncp != NULL; ncp = ncp->next) {
-//if (fdi > 1) printf("~1 checking %d - %d %d - %d %d - %d\n", ncp->min[0], ncp->max[0], ncp->min[1], ncp->max[1], ncp->min[2], ncp->max[2]);
- for (f = 0; f < fdi; f++) {
- if (ncp->min[f] != imin[f]
- || ncp->max[f] != imax[f]) {
-//if (fdi > 1) printf("~1 not a match\n");
- break;
+ /* Triangle vertex index numbers */
+ for (j = 0; j <= sdi; j++) {
+ triix[j] = vx->ix + tri->ti[k].goffs[j];
+
+ if ((trivx[j] = get_vtxrec(&vc, triix[j])) == NULL) {
+ break; /* Vertex doesn't exist */
+ }
+ if (trivx[j]->status != vtx_norm)
+ ntvsh++;
+ else
+ nntvsh++;
+ }
+
+ /* If a vertex isn't valid, or all vertexes are shadowed or not shadowed */
+ if (j <= sdi
+ || ntvsh == (sdi+1)
+ || nntvsh == (sdi+1)) {
+//printf("~1 vtx missing %d, ntvsh %d, nntvxsh %d\n",j <= sdi, ntvsh, nntvsh);
+ continue; /* Skip this triangle */
+ }
+
+ /* If triangle has been done before for this bxcell, skip it. */
+ if (check_trirec(s, &tc, triix)) {
+ continue;
+ }
+
+ /* We've decided to add triangle and test vertex */
+ if (!added) {
+ add_vtxrec_list(&vc, vx, 1); /* Add vertex to list to test against */
+ added = 1;
+ }
+
+ /* Create or re-use test vertex */
+ if (ftlist != NULL) { /* Grab one from free list */
+ tvx = ftlist;
+ ftlist = tvx->tlist;
+ memset((void *)tvx, 0, sizeof(tvxrec));
+
+ } else {
+ if ((tvx = (tvxrec *) rev_calloc(s, 1, sizeof(tvxrec))) == NULL)
+ error("rspl malloc failed - rev tvxrec structs");
+ INCSZ(s, sizeof(tvxrec));
+ }
+
+ tvx->tlist = tlist;
+ tlist = tvx;
+ nitlist++;
+
+ for (f = 0; f < fdi; f++)
+ tvx->v[f] = 0.0;
+
+ for (j = 0; j <= sdi; j++) {
+ if (trivx[j]->status == vtx_norm) {
+ for (f = 0; f < fdi; f++)
+ tvx->v[f] += 0.95/nntvsh * trivx[j]->v[f];
+ } else {
+ for (f = 0; f < fdi; f++)
+ tvx->v[f] += 0.05/ntvsh * trivx[j]->v[f];
+ trivx[j]->cross = 1; /* For diagnostics */
+ }
+ }
+
+ /* Compute distance of test vertex to overall center point squared */
+ tvx->dist = 0.0;
+ for (f = 0; f < fdi; f++) {
+ double tt = tvx->v[f] - s->rev.ocent[f];
+ tvx->dist += tt * tt;
+ }
+
+ /* Note the triangles vertexes indexes */
+ for (j = 0; j <= sdi; j++)
+ tvx->ix[j] = trivx[j]->ix;
+#ifdef REVTABLESTATS
+ notverts++;
+#endif
}
}
- if (f >= fdi) {
-//if (fdi > 1) printf("~1 got a match\n");
- break; /* Found a matching cache entry */
- }
- }
- if (ncp != NULL) {
- rp = ncp->rip;
-//if (fdi > 1) printf("~1 got cache hit hashk = %d, with ref count %d\n\n",hashk, rp[1]);
- rp[2]++; /* Increase reference count */
+ /* Do a first pass for each test vertex, testing against */
+ /* just the triangles that are associated with it's triangle. */
+ /* (This quickly culls the test vertex list size, greatly */
+ /* reducing the time taken in the second pass */
- } else {
- /* This section seems to be the most time consuming part of the nnrev setup. */
+ /* For each test vertex */
+ for (tvx = tlist; tvx != NULL; tvx = tvx->tlist) {
+ double pv[MXRO]; /* Vertex being tested */
+ double de[MXRO]; /* Line delta */
- /* Allocate a cache entry and place it */
- if ((ncp = (nncache *)calloc(1, sizeof(nncache))) == NULL)
- error("rspl malloc failed - rev.nn cach record");
+ clear_trirec(s, &stc);
- for (f = 0; f < fdi; f++) {
- ncp->min[f] = imin[f];
- ncp->max[f] = imax[f];
- }
- ncp->next = nnc[hashk];
- nnc[hashk] = ncp;
+ /* Compute line delta */
+ for (f = 0; f < fdi; f++) {
+ pv[f] = tvx->v[f];
+ de[f] = pv[f] - s->rev.ocent[f];
+ }
- /* Convert the nn destination vertex range into an output value range. */
- for (f = 0; f < fdi; f++) {
- double gw = s->rev.gw[f];
- double gl = s->rev.gl[f];
- rmin[f] = gl + imin[f] * gw;
- rmax[f] = gl + imax[f] * gw;
- }
+ /* Setup line cla and clb */
+ init_line_eq_imp(s, NULL, &cla, clb, s->rev.ocent, de, 0);
+
+ /* For each vertex of the test vertex triangle */
+ for (jj = 0; jj <= sdi; jj++) {
+ assdire *tri; /* Triangle table */
+ float *fp;
+ int fl;
+
+ if ((vx = get_vtxrec(&vc, tvx->ix[jj])) == NULL)
+ error("rev crossing test - failed to get vertex");
+
+ if (vx->status != vtx_norm)
+ continue;
+
+ fp = s->g.a + vx->ix * s->g.pss; /* This vertex in fwd grid */
+ fl = FLV(fp); /* Edge flags for this vertex */
+ tri = tridir + fl;
+
+ /* For all +ve triangles that use this vertex */
+ for (k = 0; k < tridir[fl].no; k++) {
+ int triix[MXRI+1];
+ vtxrec *trivx[MXRI+1];
+ double v[MXRI+1][MXRO]; /* Triangle vertex values */
+ double gc[MXRO], cc, dw; /* Triangle shadow group info. */
+ int ntvsh = 0; /* Number of verticies shadowed */
+ double bdist = -1.0;
+ double tb[MXRI]; /* Solution point in input space */
+ double xv[MXRO]; /* Solution point in output space */
+ int g, sorv, wsrv; /* Solved & within simplex return value */
+ double dist; /* distance to line origin */
+ double dot; /* dot product of solution to line */
+
+//printf("~1 tri %d: goffs = %s\n", i, debPiv(sdi+1, tri->ti[k].goffs));
+
+ /* Triangle vertex index numbers */
+ triix[0] = vx->ix + tri->ti[k].goffs[0];
+ triix[1] = vx->ix + tri->ti[k].goffs[1];
+ triix[2] = vx->ix + tri->ti[k].goffs[2];
+
+ /* If triangle has been done before for this tvx, skip it. */
+ if (check_trirec(s, &stc, triix)) {
+ continue;
+ }
+
+ /* Triangle vertex index numbers */
+ for (j = 0; j <= sdi; j++) {
+// triix[j] = vx->ix + tri->ti[k].goffs[j];
- /* Do any adjustment of the range needed to acount for the inacuracies */
- /* caused by the vertex quantization. */
- /* (I don't really understand the need for the extra avggw expansion, */
- /* but there are artefacts without this. This size of this sampling */
- /* expansion has a great effect on the performance.) */
+ if ((trivx[j] = get_vtxrec(&vc, triix[j])) == NULL) {
+ break; /* Vertex doesn't exist */
+ }
+ if (trivx[j]->status != vtx_norm)
+ ntvsh++;
+
+ if (trivx[j]->dist > bdist)
+ bdist = trivx[j]->dist;
+ }
+
+ /* If vertex is above triangle, it can't be shadowed */
+ if (tvx->dist > bdist)
+ continue;
+
+ /* If a vertex isn't valid, or all vertexes are shadowed */
+ if (j <= sdi
+ || ntvsh >= (sdi+1)) {
+ continue; /* Skip this triangle */
+ }
+
+ /* If this triangle is the test vertex triangle, skip it */
+ if (tvx->ix[0] == triix[0]
+ && tvx->ix[1] == triix[1]
+ && tvx->ix[2] == triix[2]) {
+ continue;
+ }
+
+ for (j = 0; j <= sdi; j++) {
+ for (f = 0; f < fdi; f++)
+ v[j][f] = trivx[j]->v[f];
+ }
+
+ /* Compute shadow group params of triangle for quick vertex test */
+ comp_shadow_group(s, s->rev.ocent, gc, &cc, &dw, NULL, v, sdi+1);
+
+ /* Do quick check against triangle */
+ if (!shadow_group_vertex(s,
+ s->rev.ocent, gc, cc, dw, tvx->v)) {
+ continue;
+ }
+
+//printf("~1 checking vertex %d at %s dist %f\n",tvx->ix, debPdv(fdi,tvx->v), sqrt(tvx->dist));
+ /* Compute intersection: */
+ wsrv = 0;
+
+ /* Solve line/triangle intersection using same */
+ /* method as vnearest_clip_solve(). */
+
+ /* LHS: ta[sdi][sdi] = cla[sdi][fdi] * vv[fdi][sdi] */
+ /* RHS: tb[sdi] = clb[sdi] - cla[sdi][fdi] * vv_di[fdi] */
+ for (f = 0; f < sdi; f++) {
+ double tt;
+ for (e = 0; e < sdi; e++) {
+ for (tt = 0.0, g = 0; g < fdi; g++)
+ tt += cla[f][g] * (v[e][g] - v[e+1][g]);
+ ta[f][e] = tt;
+ }
+ for (tt = 0.0, g = 0; g < fdi; g++)
+ tt += cla[f][g] * v[sdi][g];
+ tb[f] = clb[f] - tt;
+ }
+
+ /* Compute the solution */
+ /* (Solve the simultaneous linear equations A.X = B) */
+// sorv = !solve_se(ta, tb, sdi);
+ sorv = !solve_se_2x2(ta, tb); /* Saves a few % only */
+
+ if (!sorv)
+ continue;
+
+ /* Check that the solution is within the simplex & meets ink limit */
+ if ((wsrv = simple_within_simplex(v, tb, sdi)) != 0) {
+
+ /* Compute the output space solution point */
+ for (f = 0; f < fdi; f++) {
+ double tt = 0.0;
+ for (e = 0; e < sdi; e++)
+ tt += (v[e][f] - v[e+1][f]) * tb[e];
+ xv[f] = tt + v[sdi][f];
+ }
+
+ /* Compute distance to gamut center squared, */
+ /* as well as the dot product */
+ for (dot = dist = 0.0, f = 0; f < fdi ; f++) {
+ double tt = (xv[f] - s->rev.ocent[f]);
+ dist += tt * tt;
+ dot += de[f] * tt;
+ }
+
+ /* If intersection distance is greater than vertex distance, */
+ /* mark the test vertex as shadowed (== crossed triangle */
+ /* is shadowed) */
+ if (dot > 0.0 && dist > (tvx->dist + EPS)) {
+ tvx->shad = 1;
+ goto next_tvx;
+ }
+ }
+ } /* Next associated triangle */
+ } /* Next vertex of test triangle */
+ next_tvx:;
+ } /* Next test vertex */
+
+ /* Delete shadowed tvx, and sort remaining tlist by distance so */
+ /* that we have a better chance of shadowing it early ? */
{
- double avggw = 0.0;
- for (f = 0; f < fdi; f++)
- avggw += s->rev.gw[f];
- avggw /= (double)fdi;
- for (f = 0; f < fdi; f++) { /* Quantizing range plus extra */
- double gw = s->rev.gw[f];
- rmin[f] -= (0.5 * gw + 0.99 * avggw);
- rmax[f] += (0.5 * gw + 0.99 * avggw);
+ int i;
+ tvxrec **sort, *vx, *nvx;
+
+ /* Create temporary array of pointers to tvxrec's in list */
+ if ((sort = (tvxrec **) rev_calloc(s, nitlist, sizeof(tvxrec *))) == NULL)
+ error("rspl malloc failed - rev tvxrec sort array");
+ INCSZ(s, nitlist * sizeof(tvxrec *));
+
+ for (i = 0, vx = tlist; vx != NULL; vx = nvx) {
+ nvx = vx->tlist;
+ if (!vx->shad) {
+ sort[i++] = vx;
+ } else {
+ /* Put deleted tvxrec on the free list to re-use */
+ vx->tlist = ftlist;
+ ftlist = vx;
+ }
}
- }
-//if (fdi > 1) printf("~1 prime vertex value adjusted range = %f - %f, %f - %f, %f - %fn", rmin[0], rmax[0], rmin[1], rmax[1], rmin[2], rmax[2]);
+ nitlist = i;
+
+ /* Sort the list into ascending distance from center */
+#define HEAP_COMPARE(A,B) (A->dist < B->dist)
+ HEAPSORT(tvxrec *, sort, nitlist)
+#undef HEAP_COMPARE
+
+ /* Re-create the linked list in descending order */
+ tlist = NULL;
+ for (i = 0; i < nitlist; i++) {
+ vx = sort[i];
+ vx->tlist = tlist;
+ tlist = vx;
+ }
+
+ free(sort);
+ DECSZ(s, nitlist * sizeof(tvxrec *));
- /* computue the rev.rev cell grid range we will need to cover to */
- /* get all the cell output ranges that could touch our nn reverse range */
- for (f = 0; f < fdi; f++) {
- double gw = s->rev.gw[f];
- double gl = s->rev.gl[f];
- imin[f] = (int)floor((rmin[f] - gl)/gw);
- if (imin[f] < 0)
- imin[f] = 0;
- else if (imin[f] > rgres_1)
- imin[f] = rgres_1;
- imax[f] = (int)floor((rmax[f] - gl)/gw);
- if (imax[f] < 0)
- imax[f] = 0;
- else if (imax[f] > rgres_1)
- imax[f] = rgres_1;
- cc[f] = imin[f]; /* Set grid starting value */
+#ifdef NEVER
+ printf("sorted test vertex list:\n");
+ for (i = 0, vx = tlist; vx != NULL; vx = vx->tlist, i++)
+ printf("%d: ix %s dist %f\n",i,debPiv(3,vx->ix), sqrt(vx->dist));
+#endif
}
- tcount = s->get_next_touch(s); /* Get next grid touched generation count */
-//if (fdi > 1) printf("~1 Cells to scan = %d - %d, %d - %d, %d - %d\n", imin[0], imax[0], imin[1], imax[1], imin[2], imax[2]);
+ /* Be able to detect triangles already tested */
+ /* from this shadowing bxcell. */
+ clear_trirec(s, &tc);
+
+ /* sort vertexes by descending distance to center point */
+ /* (and also reset list tflag), to detect shadowing early */
+ sort_vtxrec_list(s, &vc);
+
+ /* Check if the test points are shadowed by any triangle */
+ for (vx = vc.vtxlist; vx != NULL; vx = vx->tlist) {
+ assdire *tri; /* Triangle table */
+ float *fp;
+ int fl;
- rp = NULL; /* We always allocate a new list initially */
- for (f = 0; f < fdi;) { /* For all the cells in the min/max range */
- int ii;
- int **nrpp, *nrp; /* Pointer to base of cell list, entry 0 = allocated space */
+ if (vx->status != vtx_norm) // ???
+ continue;
- /* Get pointer to rev.rev[] cell list */
- for (nrpp = s->rev.rev, f = 0; f < fdi; f++)
- nrpp += cc[f] * s->rev.coi[f];
+ fp = s->g.a + vx->ix * s->g.pss; /* This vertex in fwd grid */
+ fl = FLV(fp); /* Edge flags for this vertex */
+ tri = tridir + fl;
- if ((nrp = *nrpp) == NULL)
- goto next_range_list; /* This rev.rev[] cell is empty */
+ /* For all +ve triangles that use this vertex */
+ for (k = 0; k < tridir[fl].no; k++) {
+ int triix[MXRI+1];
+ vtxrec *trivx[MXRI+1];
+ double v[MXRI+1][MXRO]; /* Triangle vertex values */
+ double gc[MXRO], cc, dw; /* Triangle shadow group info. */
+ int ntvsh = 0; /* Number of verticies shadowed */
+ double bdist = -1.0;
+//printf("~1 tri %d: goffs = %s\n", i, debPiv(sdi+1, tri->ti[k].goffs));
-//if (fdi > 1) printf("~1 adding list from cell %d, list length %d\n",nrpp - s->rev.rev, nrp[0]);
- /* For all the fwd cells in the rev.rev[] list */
- for(nrp += 3; *nrp != -1; nrp++) {
- int ix = *nrp; /* Fwd cell index */
- float *fcb = s->g.a + ix * s->g.pss; /* Pntr to base float of fwd cell */
+ /* Triangle details */
+ for (j = 0; j <= sdi; j++) {
+ triix[j] = vx->ix + tri->ti[k].goffs[j];
- if (TOUCHF(fcb) >= tcount) { /* If we seen visited this fwd cell before */
-//if (fdi > 1) printf("~1 skipping cell %d because we alread have it\n",ix);
+ if ((trivx[j] = get_vtxrec(&vc, triix[j])) == NULL) {
+ break; /* Vertex doesn't exist */
+ }
+ if (trivx[j]->status != vtx_norm)
+ ntvsh++;
+
+ if (trivx[j]->dist > bdist)
+ bdist = trivx[j]->dist;
+ }
+
+ /* If a vertex isn't valid, or all vertexes are shadowed */
+ if (j <= sdi
+ || ntvsh >= (sdi+1)) {
+ continue; /* Skip this triangle */
+ }
+
+ /* If triangle has been done before for this bxcell, skip it. */
+ if (check_trirec(s, &tc, triix)) {
continue;
}
- TOUCHF(fcb) = tcount; /* Touch it so we will skip it next time */
- /* Compute the range of output values this cell covers */
- for (f = 0; f < fdi; f++) /* Init output min/max */
- min[f] = max[f] = fcb[f];
+ for (j = 0; j <= sdi; j++) {
+ for (f = 0; f < fdi; f++)
+ v[j][f] = trivx[j]->v[f];
+ }
- /* For all other grid points in the fwd cell cube */
- for (ee = 1; ee < (1 << di); ee++) {
- float *gt = fcb + s->g.fhi[ee]; /* Pointer to cube vertex */
-
- /* Update bounding box for this grid point */
+ /* Compute shadow group params of triangle for quick vertex test */
+ comp_shadow_group(s, s->rev.ocent, gc, &cc, &dw, NULL, v, sdi+1);
+
+ /* For all test vertexes */
+ for (tvx = tlist; tvx != NULL; tvx = tvx->tlist) {
+ double pv[MXRO]; /* Vertex being tested */
+ double de[MXRO]; /* Line delta */
+ double tb[MXRI]; /* Solution point in input space */
+ double xv[MXRO]; /* Solution point in output space */
+ int g, sorv, wsrv; /* Solved & within simplex return value */
+ double dist; /* distance to line origin */
+ double dot; /* dot product of solution to line */
+
+ /* If vertex is above triangle, it can't be shadowed */
+ if (tvx->dist > bdist)
+ continue;
+
+ /* If we have already determined this one is shadowed */
+ if (tvx->shad)
+ continue;
+
+ /* If this vertex for this triangle, skip it */
+ if (tvx->ix[0] == triix[0]
+ && tvx->ix[1] == triix[1]
+ && tvx->ix[2] == triix[2]) {
+ continue;
+ }
+
+ /* Do quick check against triangle */
+ if (!shadow_group_vertex(s, s->rev.ocent, gc, cc, dw, tvx->v))
+ continue;
+//printf("~1 checking vertex %d at %s dist %f\n",tvx->ix, debPdv(fdi,tvx->v), sqrt(tvx->dist));
+ /* Compute intersection: */
+ wsrv = 0;
+
+ /* Compute line delta */
for (f = 0; f < fdi; f++) {
- if (min[f] > gt[f])
- min[f] = gt[f];
- if (max[f] < gt[f])
- max[f] = gt[f];
+ pv[f] = tvx->v[f];
+ de[f] = pv[f] - s->rev.ocent[f];
}
- }
-//if (fdi > 1) printf("~1 cell %d range = %f - %f, %f - %f, %f - %f\n", ix, min[0], max[0], min[1], max[1], min[2], max[2]);
+ /* Setup line cla and clb */
+ init_line_eq_imp(s, NULL, &cla, clb, s->rev.ocent, de, 0);
- /* See if this fwd cell output values overlaps our region of interest */
- for (f = 0; f < fdi; f++) {
- if (min[f] > rmax[f]
- || max[f] < rmin[f]) {
- break; /* Doesn't overlap */
+ /* Solve line/triangle intersection using same */
+ /* method as vnearest_clip_solve(). */
+
+ /* LHS: ta[sdi][sdi] = cla[sdi][fdi] * vv[fdi][sdi] */
+ /* RHS: tb[sdi] = clb[sdi] - cla[sdi][fdi] * vv_di[fdi] */
+ for (f = 0; f < sdi; f++) {
+ double tt;
+ for (e = 0; e < sdi; e++) {
+ for (tt = 0.0, g = 0; g < fdi; g++)
+ tt += cla[f][g] * (v[e][g] - v[e+1][g]);
+ ta[f][e] = tt;
+ }
+ for (tt = 0.0, g = 0; g < fdi; g++)
+ tt += cla[f][g] * v[sdi][g];
+ tb[f] = clb[f] - tt;
}
- }
+
+ /* Compute the solution */
+ /* (Solve the simultaneous linear equations A.X = B) */
+// sorv = !solve_se(ta, tb, sdi);
+ sorv = !solve_se_2x2(ta, tb); /* Saves a few % only */
- if (f < fdi) {
-//if (fdi > 1) printf("~1 skipping cell %d because we doesn't overlap\n",ix);
- continue; /* It doesn't overlap */
+ /* If it was solved */
+ if (sorv) {
+
+ /* Check that the solution is within the simplex & ink limit */
+ if ((wsrv = simple_within_simplex(v, tb, sdi)) != 0) {
+
+ /* Compute the output space solution point */
+ for (f = 0; f < fdi; f++) {
+ double tt = 0.0;
+ for (e = 0; e < sdi; e++)
+ tt += (v[e][f] - v[e+1][f]) * tb[e];
+ xv[f] = tt + v[sdi][f];
+ }
+
+ /* Compute distance to gamut center squared, */
+ /* as well as the dot product */
+ for (dot = dist = 0.0, f = 0; f < fdi ; f++) {
+ double tt = (xv[f] - s->rev.ocent[f]);
+ dist += tt * tt;
+ dot += de[f] * tt;
+ }
+//printf("~1 intersection at %s dist %f\n", debPdv(fdi,xv), sqrt(dist));
+
+ /* If intersection distance is greater than vertex distance, */
+ /* mark the test vertex as shadowed (== crossed triangle */
+ /* is shadowed) */
+ if (dot > 0.0 && dist > (tvx->dist + EPS)) {
+ tvx->shad = 1;
+ }
+ }
+ }
+ } /* Next test vertex */
+ } /* Next triangle from vertex */
+ } /* Next vertex */
+
+ /* Go through test vertex results, and if it is un-shadowed, */
+ /* mark all the corresponding triangle vertexes as un-shadowed. */
+ /* For all test vertexes */
+ for (tvx = tlist; tvx != NULL; tvx = ntvx) {
+ ntvx = tvx->tlist;
+
+ /* If the test point wasn't shadowed, assume it */
+ /* is part of the gamut surface, and mark all its */
+ /* vertexes as valid. */
+ if (!tvx->shad) {
+ for (j = 0; j <= sdi; j++) {
+ if ((vx = get_vtxrec(&vc, tvx->ix[j])) == NULL)
+ error("rev - failed to locate vertex %d\n",tvx->ix[j]);
+
+ if (vx->status != vtx_norm) {
+ vx->pres = 1; /* Don't treat it as deleted */
+ }
}
-
-//if (fdi > 1) printf("~1 adding fwd index %d to list\n",ix);
-//if (fdi > 1) printf("~1 cell %d range = %f - %f, %f - %f, %f - %f\n", ix, min[0], max[0], min[1], max[1], min[2], max[2]);
-#ifdef DEBUG
- fwdcells++;
-#endif
- /* It does, add it to our new list */
- if (rp == NULL) {
- if ((rp = (int *) rev_malloc(s, 6 * sizeof(int))) == NULL)
- error("rspl malloc failed - rev.nngrid entry");
- INCSZ(s, 6 * sizeof(int));
- rp[0] = 6; /* Allocation */
- rp[1] = 4; /* Next free Cell */
- rp[2] = 1; /* reference count */
- rp[3] = ix;
- rp[4] = -1;
+ }
+ /* Put all the tvxrec's on the free list to re-use */
+ tvx->tlist = ftlist;
+ ftlist = tvx;
+ }
+ tlist = NULL;
+ nitlist = 0;
+
+ /* If the preseved vertexes have been deleted from the bx list, */
+ /* add them back in again */
+ if (bx->dl != NULL) {
+ for (nrp = rp = bx->dl+3; *rp != -1; rp++) {
+ vtxrec *vx;
+
+ if ((vx = get_vtxrec(&vc, *rp)) == NULL)
+ continue; /* Hmm. */
+
+ /* If preserved, transfer it to the active bx list */
+ if (vx->pres) {
+ add2indexlist(s, &bx->sl, *rp, 0);
+
+ /* Leave it in deleted list */
} else {
- int z = rp[1], ll = rp[0];
- if (z >= (ll-1)) { /* Not enough space */
- INCSZ(s, ll * sizeof(int));
- ll *= 2;
- if ((rp = (int *) rev_realloc(s, rp, sizeof(int) * ll)) == NULL)
- error("rspl realloc failed - rev.grid entry");
- rp[0] = ll;
- }
- rp[z++] = ix;
- rp[z] = -1;
- rp[1] = z;
+ *nrp++ = *rp;
}
- } /* Next fwd cell in list */
-
- /* Increment index */
- next_range_list:;
- for (f = 0; f < fdi; f++) {
- if (++cc[f] <= imax[f])
- break; /* No carry */
- cc[f] = imin[f];
}
+ *nrp = -1;
+ bx->dl[1] = nrp - bx->dl;
+
+ /* We don't need the deleted list now */
+ free_indexlist(s, &bx->dl);
}
- ncp->rip = rp; /* record nnrev cell in cache */
-#ifdef DEBUG
- cellinrevlist++;
-#endif
-//if (fdi > 1) printf("~1 adding cache entry with hashk = %d\n\n",hashk);
+ } /* Next bxcell */
+
+ /* Free up tvxrec's */
+ while (ftlist != NULL) {
+ tvxrec *this = ftlist;
+ ftlist = ftlist->tlist;
+ free(this);
+ DECSZ(s, sizeof(tvxrec));
}
- /* Put the resulting list in place */
- if (prime != NULL)
- prime->clist = rp; /* Save it untill we get rid of the primes */
- else
- *rpp = rp;
+#ifdef REVTABLESTATS
+ /* Count the number of preserved vertexes */
+ for (i = 0; i < vc.hash_size; i++) {
+ for (vx = vc.hash[i]; vx != NULL; vx = vx->hlink) {
+ if (vx->pres)
+ nopreserved++;
+ }
+ }
+ printf("%d crossed triangles tested\n",notverts);
+ printf("%d hidden verticies retained for crossed triangles\n",nopreserved);
+ printf("Took %f secs to preserving crossing triangless\n",0.001 * (msec_time()-lmsec));
+#endif
+ } /* End of preserve shadowed triangles */
-//if (*rpp == NULL) printf("~1 problem: we ended up with no list or prime struct at cell %d\n",i);
+ /* = = = = = = = = = = = = = = = = = = */
+ /* Delete any shadowed vertexes, and remove any empty bxcells. */
+ for (pbx = &s->rev.surflist, bx = *pbx; bx != NULL; bx = nbx) {
+ int *rp, *nrp;
-#ifdef NEVER
-/* Sanity check the list, to see if the list cells corner contain an output value */
-/* that is at least closer to the target than the prime. */
-if (prop != NULL) {
- int *tp = rp;
- double bdist = 1e60;
- double bdist2 = 1e60;
- double vx[MXRO]; /* Vertex location */
- double px[MXRO]; /* Prime location */
- double cl[MXRO]; /* Closest output value from list */
- double acl[MXRO]; /* Absolute closest output value */
- double dst; /* Distance to prime */
- int ti;
-
- primevx *prm = (primevx *) *(s->rev.nnrev + prop->cix);
- for (f = 0; f < fdi; f++) {
- double gw = s->rev.gw[f];
- double gl = s->rev.gl[f];
- vx[f] = gl + prop->gc[f] * gw;
- px[f] = gl + prm->gc[f] * gw;
- }
+ /* Delete all the shadowed or delted vertexes from bxcell list, */
+ /* unless they are preserved because they are part of a crossed triangle. */
+ for (nrp = rp = bx->sl+3; *rp != -1; rp++) {
+ vtxrec *vx;
- for(tp++; *tp != -1; tp++) {
- int ix = *tp; /* Fwd cell index */
- float *fcb = s->g.a + ix * s->g.pss; /* Pntr to base float of fwd cell */
+ if ((vx = get_vtxrec(&vc, *rp)) == NULL)
+ continue; /* Hmm. */
- for (ee = 0; ee < (1 << di); ee++) {
- double ss;
- float *gt = fcb + s->g.fhi[ee]; /* Pointer to cube vertex */
-
- for (ss = 0.0, f = 0; f < fdi; f++) {
- double tt = vx[f] - gt[f];
- ss += tt * tt;
+ /* Keep all the un-shadowed or preserved vertexes */
+ if (vx->status == vtx_norm
+ || vx->pres) {
+ *nrp++ = *rp;
+ } else {
+ del_vtxrec_hash(&vc, vx->ix);
+ }
}
- if (ss < bdist) {
- bdist = ss;
- for (f = 0; f < fdi; f++)
- cl[f] = gt[f];
+ *nrp = -1;
+ bx->sl[1] = nrp - bx->sl;
+
+ if (bx->sl == NULL /* Missing or empty fwd index list */
+ || bx->sl[1] == 3
+ ) {
+ /* Remove it from vflag array */
+ if (s->rev.rev[bx->ix] != NULL) {
+ vflag[bx->ix] = (vflag[bx->ix] & ~0xf) | 1; /* Not surface and done */
+ } else {
+ vflag[bx->ix] = (vflag[bx->ix] & ~0xf) | 0; /* Not surface and empty */
+ }
+
+ /* Remove it from hash */
+ rem_bxcell_hash(s, bx->ix);
+
+ /* Free fwd index list (none are shared at this point) */
+ if (bx->sl != NULL)
+ free_indexlist(s, &bx->sl);
+
+ /* Remove it from surface list */
+ *pbx = nbx = bx->slist;
+
+ /* Free it */
+ del_bxcell(s, bx);
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ nrscells++;
+#endif
+
+ } else { /* Move on to next */
+ pbx = &bx->slist;
+ nbx = bx->slist;
}
}
- }
- bdist = sqrt(bdist);
- dst = sqrt(prop->dsq);
- /* Lookup best distance to any output value */
- if (dst < bdist) {
- float *gt;
- for (ti = 0, gt = s->g.a; ti < s->g.no; ti++, gt += s->g.pss) {
- double ss;
-
- for (ss = 0.0, f = 0; f < fdi; f++) {
- double tt = vx[f] - gt[f];
- ss += tt * tt;
- }
- if (ss < bdist2) {
- bdist2 = ss;
- for (f = 0; f < fdi; f++)
- acl[f] = gt[f];
+ /* Add extra over ink limit vertexes. */
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int sdi = 1; /* sub-simplexes are edges */
+ int *crp, *rp, *nrp;
+ int ttouch;
+ vtxrec *vx, *nvx;
+
+ /* Add over ink limit vertexes, so that fwd cells will straddle */
+ /* the ink limit boundary. */
+ /* Do this by checking all vertexes edge neighbors, */
+ /* and adding any that are over the ink limit. */
+ /* (Only do this for bx cells that are known to contain */
+ /* over ink limit verticies.) */
+ if (s->limiten && vflag[bx->ix] & 0x10) {
+ int *rp;
+//printf("~1 ink limitin is enabled bx %d\n", bx->ix);
+
+ for (rp = bx->sl+3; *rp != -1; rp++) {
+ float *vp, *evp;
+ int fl;
+ assdire *edg; /* Edge table */
+
+ if ((vx = get_vtxrec(&vc, *rp)) == NULL)
+ continue; /* Hmm. */
+
+ /* Don't do this for preserved or oil vertexes */
+ if (vx->status != vtx_norm)
+ continue;
+
+ vp = s->g.a + vx->ix * s->g.pss; /* This vertex in fwd grid */
+ fl = FLV(vp); /* Edge flags for this vertex */
+ edg = edgdir + fl;
+
+#ifdef CHECK_NNLU
+ if (vp[-1] > s->limitv)
+ error("Thinned vertex %d is over ink limit!",vx->ix);
+#endif
+
+//printf("~1 fl %d = 0o%o, no edges %d\n",fl, fl, edg->no);
+
+ /* For all possible edges that use this vertex */
+ for (i = 0; i < edgdir[fl].no; i++) {
+ int eix;
+
+//printf("~1 edg %d: goffs = %s\n", i, debPiv(sdi+1, edg->ti[i].goffs));
+
+ /* Edge vertex index number of other vertex */
+ if (edg->ti[i].goffs[0] != 0)
+ eix = vx->ix + edg->ti[i].goffs[0];
+ else
+ eix = vx->ix + edg->ti[i].goffs[1];
+
+ evp = s->g.a + eix * s->g.pss; /* Other vertex in fwd grid */
+
+//printf(" Checking edge %d (%f) -> %d (%f)\n", vx->ix, vp[-1], eix, evp[-1]);
+
+ /* If over limit, add it to the list */
+ if (evp[-1] > s->limitv) {
+//printf("~1 added over ink limit vertex %d\n",eix);
+
+ if (get_vtxrec(&vc, eix) != NULL)
+ continue; /* Added by another bx */
+ nvx = new_vtxrec(s, &vc, eix);
+ nvx->status = vtx_oil;
+ add2indexlist(s, &bx->sl, eix, 0);
+ }
+ }
+ }
}
}
- }
- bdist2 = sqrt(bdist2);
- if (dst < bdist) {
- printf("~1 vertex %d has worse distance to values than prime\n",i);
- printf("~1 vertex loc %f %f %f\n", vx[0], vx[1], vx[2]);
- printf("~1 prime loc %f %f %f, dist %f\n", px[0], px[1], px[2],dst);
- printf("~1 closest loc %f %f %f, dist %f\n", cl[0], cl[1], cl[2],bdist);
- printf("~1 abs clst loc %f %f %f, dist %f\n", acl[0], acl[1], acl[2], bdist2);
+#ifdef REVTABLESTATS
+ /* Count the number of over ink limit vertexes */
+ for (i = 0; i < vc.hash_size; i++) {
+ vtxrec *vx;
+ for (vx = vc.hash[i]; vx != NULL; vx = vx->hlink) {
+ if (vx->status == vtx_oil)
+ naoulvtxs++;
+ }
}
-}
-#endif // NEVER
+#endif
+
+#ifdef REVVRML
+ /* Plot final vertex surface before converting to fwcells */
+ /* Vtx ix tag ? Deleted vtxs ? Added vtxs ? Preserved vtxs ? oil vtxs ? bxcells ? Wait ? */
+ if (1) plot_vtx_surface(s, 0, 0, 0, 1, 1, 0, 0, &vc, edgdir);
+#endif /* REVVRML */
+
+ /* Convert vertexes to cube lists */
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int sdi = 1; /* sub-simplexes are edges */
+ int *crp, *rp, *nrp;
+ int ttouch;
+ vtxrec *vx, *nvx;
+
+ /* If there are no vertexes left (i.e. they have all been deleted) */
+ /* Don't try and convert to fwd cells. */
+ if (bx->sl == NULL || bx->sl[1] == 3) {
+ bx->status = bx_conv;
+ continue;
+ }
+
+ /* Create cach list of vxrec's for just this nnrev[] */
+ clear_vtxrec_lists(s, &vc);
- if (prop != NULL && prime == NULL) {
- free(prop);
+ /* Add all this bxcell verticies to cache and list */
+ for (rp = bx->sl+3; *rp != -1; rp++) {
+ vx = new_vtxrec(s, &vc, *rp);
+ add_vtxrec_list(&vc, vx, 0);
}
- next_vertex:;
- DC_INC(gg);
+ /* Convert fwd index list into fwd cells list. Do this in */
+ /* a way that minimizes the number of cells needed while still */
+ /* ensuring that there is 2 dimensional connectivity for all the vertexes. */
+
+ /* Count number of touches if we add a cube for each prime vertex */
+//printf("~1 counting number of touches\n");
+ crp = bx->sl;
+ i = 0;
+ for (rp = crp+3; *rp != -1; rp++) {
+ vtxrec *vx;
+
+ if ((vx = get_vtxrec(&vc, *rp)) == NULL)
+ error("get_vtxrec() failed on surface vtx");
+
+ i++;
+
+ /* For each vertex of cube placed at vx->cix */
+ for (ee = 0; ee < (1<<di); ee++) {
+ int vix = vx->cix + s->g.hi[ee];
+ vtxrec *nx;
+
+ if ((nx = get_vtxrec(&vc, vix)) != NULL)
+ vx->tcount++;
+ }
+ }
+//printf("there were %d vertexes",i);
+
+//printf("~1 adding cells in order of touch count\n");
+ /* Add cells in order of touch count, i.e. from most necessary */
+ /* to least necessary. Allow a maximum touch of 4, to ensure */
+ /* 2 dimensional connectivity of the fwd cells */
+ nrp = NULL;
+ i = 0;
+ for (ttouch = 1; ; ttouch++) {
+ int more = 0;
+//printf("~1 ttouch = %d\n",ttouch);
+ for (rp = crp+3; *rp != -1; rp++) {
+ vtxrec *vx = get_vtxrec(&vc, *rp);
+
+ if (vx->tcount == 0)
+ continue;
+
+ more = 1;
+ if (vx->tcount > ttouch)
+ continue;
+
+ /* For each cube vertex placed at vx->cix */
+ for (ee = 0; ee < (1<<di); ee++) {
+ int vix = vx->cix + s->g.hi[ee];
+ vtxrec *nx;
+
+ /* Track touch count on creating cells, and */
+ /* clear vertexes that have reached 4, */
+ /* so that they don't get any more */
+ if ((nx = get_vtxrec(&vc, vix)) != NULL) {
+//printf("bx %d, adding fwcell vertex %d for vertex %d\n",bx->ix,vix,*rp);
+ vx->acount++;
+ if (vx->acount >= 4)
+ vx->tcount = 0;
+ }
+ }
+ i++;
+ add2indexlist(s, &nrp, vx->cix, 0);
+ }
+ if (!more)
+ break;
+ }
+//printf(", now %d fwdcells\n",i);
+//printf("~1 replacing vertex list with cell list\n");
+
+ if (nrp == NULL)
+ error("Surface list bxcell ix %d has no fwd cells",bx->ix);
+
+ /* Replace vertex list with cell list */
+ free_indexlist(s, &bx->sl);
+ bx->sl = nrp;
+
+ if (bx->sl == NULL)
+ error("Surcface cell nnrev[%d] is empty!\n",bx->ix);
+ bx->status = bx_conv;
+ }
+
+ if (cla != NULL)
+ free_dmatrix(cla, 0, fdi-1, 0, fdi);
+ free_trirec(s, &stc);
+ free_trirec(s, &tc);
+ free_vtxrec_list(s, &vc);
+ free_assdir(s, edgdir);
+ free_assdir(s, tridir);
+ }
+
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ if (fdi > 1) {
+ bxcell *bx;
+ int surfcelldepth = 0, surfcells = 0;
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ if (bx->sl == NULL
+ || bx->sl[1] == 3)
+ continue;
+ surfcells++;
+ surfcelldepth += bx->sl[1]-3;
}
- DBG(("freeing up the prime seed structurs\n"));
- /* Finaly convert all the prime verticies to cell lists */
- /* Free up all the prime seed structures */
- for (;plist != NULL; ) {
- primevx *prime, *next = plist->next;
- int **rpp;
+ printf("%d/%d surface cells\n",surfcells,rgno);
+ printf("%d/%d non-surface cells\n",ingamutcells,rgno);
+ printf("%d/%d empty cells\n",emptycells,rgno);
+ printf("%d/%d used cells in rev[]\n",revcells,rgno);
+ printf("%f average rev[] list length\n",(double)revcelldepth/(double)revcells);
+ printf("%f average nnrev[] surface list length\n",(double)surfcelldepth/(double)surfcells);
+ printf("%d added surface cells\n",nascells);
+ printf("%d removed surface cells\n",nrscells);
+ printf("%d added over ink limit vertexes\n",naoulvtxs);
+ }
+#endif
- rpp = s->rev.nnrev + plist->ix;
- if ((prime = (primevx *)(*rpp)) != NULL) {
- if (prime->clist != NULL) /* There is a nn list for this cell */
- *rpp = prime->clist;
+#ifdef REVVRML
+ /* Plot the thinned surface fwd cells */
+ /* fwd cell base ix's ? bxcells ? Wait ? */
+ if (1 && fdi > 1) plot_fxcell_surface(s, 0, 0, 0);
+#endif /* REVVRML */
+
+ /* Fill the non-surface nnrev array from the surface list. */
+ {
+ bxcell *seedlist = NULL; /* Linked list of active seeds */
+ bxcell *seedlistend = NULL; /* Last item on seedlist */
+ bxcell *xlist = NULL; /* Linked list of cells being searched */
+ bxcell *xlistend = NULL; /* Last item on xlist */
+ bxcell *tlist; /* Linked list of cells being considered as soln. */
+ double emax; /* Current smallest estimated max weigted distance */
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ unsigned long smsec = msec_time();
+#endif
+
+ DBG(("Filling in rev.nnrev[] grid\n"));
+
+ /* Start the seeding of the nnrev[] array with all the surface cells */
+ {
+ bxcell *ss;
+
+ for (ss = s->rev.surflist; ss != NULL; ss = ss->slist) {
+ /* Add to end of seedlist */
+ ss->flist = NULL;
+ if (seedlist == NULL)
+ seedlist = ss;
else
- *rpp = NULL;
- free(prime);
- } else {
- error("assert, prime cell %d was empty",plist->ix);
+ seedlistend->flist = ss;
+ seedlistend = ss;
+
+ vflag[ss->ix] |= 1; /* They are on seed list, so will be filled */
}
- plist = next;
}
-#ifdef DEBUG
- DBG(("sanity check that all rev accell cells are filled\n"));
- DC_INIT(gg);
- for (i = 0; i < rgno; i++) {
- for (f = 0; f < fdi; f++) {
- if (gg[f] > rgres_1) { /* Vertex outside bwd cell range, */
- goto next_vertex3;
+ /* While there are nnrev[] cells to fill */
+ while (seedlist != NULL) {
+ DCOUNT(cc, MXRO, fdi, -1, -1, 2); /* bwd neighborhood offset counter */
+ int nix; /* Neighbor offset index */
+ bxcell *ss, *tx;
+
+ tx = seedlist; /* Remove target cell from front of seed list */
+ seedlist = tx->flist;
+
+ if (s->rev.nnrev[tx->ix] != NULL)
+ error("nncel[%d] in seed list is not empty\n",tx->ix);
+
+#ifdef CHECK_NNLU
+ if (tx->ss == NULL || (vflag[tx->ss->ix] & 2) == 0 ) {
+ if (tx->ss == NULL)
+ printf("nnrev[%d] has NULL seed\n",tx->ix);
+ else
+ printf("nnrev[%d] has seed %d with flag %x != 3\n",tx->ix,tx->ss->ix, vflag[tx->ss->ix]);
+ }
+#endif
+
+ DBG(("Doing nnrev[%d] vflag %x co %s\n",tx->ix, vflag[tx->ix], debPiv(s->fdi, tx->gc)));
+//printf("Doing nnrev[%d] vflag %x co %s\n",tx->ix, vflag[tx->ix], debPiv(s->fdi, tx->gc));
+
+ emax = 1e200; /* Smallest emax */
+ ss = tx->ss; /* Search start cell */
+ ss->tix = tx->ix; /* Mark this cell as being in search list */
+
+ /* Make start cell the only entry in the search list */
+ ss->xlist = NULL;
+ xlist = ss;
+ xlistend = ss;
+
+ /* Clear the solution list */
+ tlist = NULL;
+
+ /* Note that filling an nnrev[] cell using a seeded search may miss fw cells */
+ /* that should be in it, if they are in physically dis-continuous locations */
+ /* due to gamut hull convexity. LCh weighting will reduce this somewhat, and */
+ /* discontinuity is rarely a desired characteristic of a color conversion, so */
+ /* we are ignoring this issue for now. */
+
+ /* While there are cells to search for solutions */
+ while (xlist != NULL) {
+ double em, ex;
+
+ ss = xlist; /* Remove next search cell from linked list */
+ xlist = xlist->xlist;
+
+ /* Check if this cell could be in solution */
+ em = nn_grpgrp_est(s, &ex, &tx->g, &ss->g);
+ ss->emin = em;
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ nnrevcellsearch++;
+#endif
+
+ DBG(("Searching rev[%d] co %s, em %f, ex %f\n",ss->ix, debPiv(s->fdi, ss->gc), em, ex));
+//printf("Searching rev[%d] co %s, em %f, ex %f\n",ss->ix, debPiv(s->fdi, ss->gc), em, ex);
+
+ if (em < emax) { /* Yes */
+
+ /* Add it to the solution list */
+ ss->tlist = tlist;
+ tlist = ss;
+
+ DBG(("Adding it to solution list\n"));
+
+ /* Update smallest maximum */
+ /* (Will cull existing bxcell solutions with emin > emax later) */
+ if (ex < emax)
+ emax = ex;
+
+ /* Explore all neighbours, and add any surface cells that haven't been */
+ /* searched for this target yet. */
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ bxcell *nbx;
+
+ nix = ss->ix;
+ for (f = 0; f < fdi; f++) {
+ nn[f] = ss->gc[f] + cc[f];
+ if (nn[f] < 0 || nn[f] >= rgres)
+ break; /* Out of bounds */
+ nix += cc[f] * s->rev.coi[f];
+ }
+ if (f < fdi || nix == ss->ix) {
+//printf("Rejecting search neigbor co %s because out of bounds or current cell\n",debPiv(s->fdi,cc));
+ goto next_neighbor;
+ }
+
+ /* We only search surface bxcells */
+ if ((vflag[nix] & 2) == 0) {
+//printf("Rejecting search neigbor nnrev[%d] co %s because flags = %x\n",nix, debPiv(s->fdi, cc),vflag[nix]);
+ goto next_neighbor;
+ }
+
+ /* If neighbor is in bounds, and a surface bxcell*/
+ {
+
+ /* Expect all all surface bxcells to be in cache */
+ if ((nbx = get_surface_bxcell(s, nix)) == NULL)
+ error("rspl rev get_surface_bxcell %d failed",nix);
+
+ /* If not already in search list */
+ if (nbx->tix != tx->ix) {
+// DBG(("Adding search neigbor nnrev[%d] co %s to search list\n",nbx->ix, debPiv(s->fdi, nbx->gc)));
+//printf("Adding search neigbor nnrev[%d] co %s to search list\n",nbx->ix, debPiv(s->fdi, nbx->gc));
+ /* Add neigbor to end of search list */
+ nbx->tix = tx->ix; /* Is now in search list */
+ nbx->xlist = NULL;
+ if (xlist == NULL)
+ xlist = nbx;
+ else
+ xlistend->xlist = nbx;
+ xlistend = nbx;
+ }
+//else
+//printf("Rejecting search neigbor nnrev[%d] co %s because already in list\n",nbx->ix, debPiv(s->fdi, nbx->gc));
+ }
+ next_neighbor:;
+ DC_INC(cc);
+ }
+ }
+//else
+//printf("Rejected rev[%d] co %s, because em %f >= emax %f\n",ss->ix, debPiv(s->fdi, ss->gc), em, emax);
+ }
+
+ /* Create the nnrev[] list from the candidate bxcell solutions */
+ if (tlist != NULL) {
+ create_nnrev_list(s, tx, tlist, emax);
+ }
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ nnrevcells++;
+ nnrevcelldepth += s->rev.nnrev[tx->ix][1]-3;
+ if (s->rev.nnrev[tx->ix][1]-3 > nnmxrevcelldepth)
+ nnmxrevcelldepth = s->rev.nnrev[tx->ix][1]-3;
+#endif
+
+ /* If this was a super-cell, explore the 2nd row around this cell, */
+ /* and locate any cells not on the seeding list */
+ if (tx->scell != NULL) {
+ DCOUNT(sc, MXRO, fdi, -3, -3, 4);
+ DC_INIT(sc);
+ while (!DC_DONE(sc)) {
+ int co[MXRO];
+ int ok = 0;
+ int nix = tx->ix;
+
+ for (f = 0; f < fdi; f++) {
+ co[f] = tx->gc[f] + sc[f];
+ if (co[f] < 0 || co[f] >= s->rev.res)
+ break;
+ nix += sc[f] * s->rev.coi[f];
+ if (sc[f] == -3 || sc[f] == 3)
+ ok = 1; /* Just surface of +/- 2 */
+ }
+ if (!ok && sc[0] == -2)
+ sc[0] = 2; /* Skip center */
+
+ /* Put this cell on list and stop searching. */
+ if (f >= fdi && (vflag[nix] & 1) == 0) {
+
+ if ((vflag[nix] & 2) != 0) { /* If un-filled surface bxcell */
+ /* Get surface bxcell from cache index for seed */
+ if ((ss = get_surface_bxcell(s, nix)) == NULL)
+ error("rspl rev get_surface_bxcell %d failed #2, vflag = %x",nix,vflag[nix]);
+//printf("Fetched surface bxcell seed %d vflag %x\n",ss->ix, vflag[ss->ix]);
+ } else { /* If un-filled nnrev */
+ if (get_surface_bxcell(s, nix) != NULL)
+ error("vflag[%d] = %x, but cell is in surface list hash\n");
+
+ /* Create new temporary (non-surface) bxcell seed. */
+ /* If we are sufficiently far from the seed point, */
+ /* a super-cell to improve seeding performance will be created. */
+ ss = new_bxcell(s, nix, co, tx->ss, tx->sdist, vflag);
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ if (tx->scell != NULL)
+// nnsuperfill += tx->scell[3]-3;
+ nnsuperfill++;
+ else
+ nnsinglefill++;
+#endif
+//printf("Created temporary seed bxcell %d vflag %x\n",ss->ix, vflag[ss->ix]);
+ }
+ DBG(("Adding seed neighbor nnrev[%d] vflag %x co %s to seed list\n",ss->ix, vflag[ss->ix], debPiv(s->fdi, ss->gc)));
+//printf("Adding seed neighbor nnrev[%d] vflag %x co %s to seed list\n",ss->ix, vflag[ss->ix], debPiv(s->fdi, ss->gc));
+
+ /* Add to end of seedlist */
+ ss->flist = NULL;
+ if (seedlist == NULL)
+ seedlist = ss;
+ else
+ seedlistend->flist = ss;
+ seedlistend = ss;
+ vflag[ss->ix] |= 1; /* This is on seed list, so will be filled */
+ }
+ DC_INC(sc);
}
+ } else {
+ /* Explore neighbours, and add any nnrev[] cells that haven't been */
+ /* put on the seed list yet. */
+ for (f = 0; f < fdi; f++)
+ cc[f] = tx->gc[f];
+ nix = tx->ix;
+
+ for (ff = 0; ff < (fdi << 1); ff++) {
+ f = ff >> 1; /* Dimension being explored */
+
+ cc[f] += (ff & 1) ? 1 : -1;
+ nix += (ff & 1) ? s->rev.coi[f] : -s->rev.coi[f];
+
+ /* If found unfilled nnrev[] cell */
+ if (cc[f] >= 0 && cc[f] < rgres && (vflag[nix] & 1) == 0) {
+
+ if ((vflag[nix] & 2) != 0) { /* If un-filled surface bxcell */
+ /* Get surface bxcell from cache index for seed */
+ if ((ss = get_surface_bxcell(s, nix)) == NULL)
+ error("rspl rev get_surface_bxcell %d failed #2, vflag = %x",nix,vflag[nix]);
+//printf("Fetched surface bxcell seed %d vflag %x\n",ss->ix, vflag[ss->ix]);
+ } else { /* If un-filled nnrev */
+ if (get_surface_bxcell(s, nix) != NULL)
+ error("vflag[%d] = %x, but cell is in surface list hash\n");
+
+ /* Create new temporary (non-surface) bxcell seed. */
+ /* If we are sufficiently far from the seed point, */
+ /* a super-cell to improve seeding performance will be created. */
+ ss = new_bxcell(s, nix, cc, tx->ss, tx->sdist, vflag);
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ if (tx->scell != NULL)
+// nnsuperfill += tx->scell[3]-3;
+ nnsuperfill++;
+ else {
+ nnsinglefill++;
+ }
+#endif
+//printf("Created temporary seed bxcell %d vflag %x\n",ss->ix, vflag[ss->ix]);
+ }
+ DBG(("Adding seed neighbor nnrev[%d] vflag %x co %s to seed list\n",ss->ix, vflag[ss->ix], debPiv(s->fdi, ss->gc)));
+//printf("Adding seed neighbor nnrev[%d] vflag %x co %s to seed list\n",ss->ix, vflag[ss->ix], debPiv(s->fdi, ss->gc));
+
+ /* Add to end of seedlist */
+ ss->flist = NULL;
+ if (seedlist == NULL)
+ seedlist = ss;
+ else
+ seedlistend->flist = ss;
+ seedlistend = ss;
+ vflag[ss->ix] |= 1; /* This is on seed list, so will be filled */
+ }
+
+ cc[f] -= (ff & 1) ? 1 : -1;
+ nix -= (ff & 1) ? s->rev.coi[f] : -s->rev.coi[f];
+ }
}
- if (*(s->rev.nnrev + i) == NULL
- && *(s->rev.rev + i) == NULL) {
-// printf("~1 warning, cell %d [ %d %d %d] has a NULL list\n",i, gg[0],gg[1],gg[2]);
- error("cell %d has a NULL list\n",i);
+ /* if this is a temporary bxcell (i.e. not a surface bxcell), */
+ /* we can now free it */
+ if ((vflag[tx->ix] & 2) == 0) {
+//printf("Done with non-surface bxcell %d vflag %x\n",tx->ix,vflag[tx->ix]);
+ del_bxcell(s, tx);
}
- next_vertex3:;
- DC_INC(gg);
}
-#endif /* DEBUG */
+ /* We've done the nnrev[] setup */
+ DBG(("rev.nnrev[] grid done - cleaning up\n"));
+
+#ifdef CHECK_NNLU
+ if (fdi > 1) {
+ /* Check that every nnrev[] cell is filled */
+ printf("Checking all %d nnrev[] cells are filled\n",rgno);
+ for (i = 0; i < rgno; i++) {
+ if ( ((vflag[i] & 2) != 0 || s->rev.rev[i] == NULL || s->rev.rev[i][1] == 3)
+ && (s->rev.nnrev[i] == NULL || s->rev.nnrev[i][1] == 3)) {
+ printf("Found empty nnrev[%d] ?:\n",i);
+ printf(" vflag %x\n",vflag[i]);
+ if (s->rev.nnrev[i] == NULL)
+ printf(" nnrev = NULL\n");
+ else
+ printf(" nnrev length = %d\n",s->rev.nnrev[i][1]-3);
+ if (s->rev.rev[i] == NULL)
+ printf(" rev = NULL\n");
+ else
+ printf(" rev = length = %d\n",s->rev.rev[i][1]-3);
+ }
+ }
+ }
+#endif /* CHECK_NNLU */
/* Free up flag array used for construction */
if (vflag != NULL) {
@@ -6136,58 +11171,37 @@ if (prop != NULL) {
free(vflag);
}
- /* Free up nn list cache indexing structure used in construction */
- if (nnc != 0) {
- for (i = 0; i < nncsize; i++) {
- nncache *nncp;
- /* Run through linked list freeing entries */
- for (ncp = nnc[i]; ncp != NULL; ncp = nncp) {
- nncp = ncp->next;
- free(ncp);
- }
- }
- free(nnc);
- nnc = NULL;
- }
- }
-
- if (s->rev.rev_valid == 0 && di > 1) {
- rev_struct *rsi;
- size_t ram_portion = g_avail_ram;
-
- /* Add into linked list */
- s->rev.next = g_rev_instances;
- g_rev_instances = &s->rev;
-
- /* Aportion the memory, and reduce cache if it is over new limit. */
- g_no_rev_cache_instances++;
- ram_portion /= g_no_rev_cache_instances;
- for (rsi = g_rev_instances; rsi != NULL; rsi = rsi->next) {
- revcache *rc = rsi->cache;
+#ifndef CHECK_NNLU
+ /* Free up surface linked list and delete the bxcells. */
+ free_surflist(s);
+#endif
- rsi->max_sz = ram_portion;
- while (rc->nunlocked > 0 && rsi->sz > rsi->max_sz) {
- if (decrease_revcache(rc) == 0)
- break;
- }
-//printf("~1 rev instance ram = %d MB\n",rsi->sz/1000000);
+ /* Free up surface bxcell hash index */
+ free_surfhash(s, 0);
+
+#if defined(REVTABLESTATS) || defined(DEBUG)
+ if (fdi > 1) {
+ nnrevshare = nnrevcells;
+ for (i = 0; i < s->rev.sharellen; i++)
+ nnrevshare += (s->rev.sharelist[i][1]-4) * (s->rev.sharelist[i][1]-3);
+
+ printf("%d/%d used cells in nnrev list\n",nnrevcells,rgno);
+ printf("%f average cells searched\n",(double)nnrevcellsearch/(double)nnrevcells);
+ printf("%d max bxcells used\n",maxbxcount);
+ printf("%.1f%% super-cell filled\n",100.0 * nnsuperfill/(nnsuperfill+nnsinglefill));
+ printf("%f average list length\n",(double)nnrevcelldepth/(double)nnrevcells);
+ printf("%d max list length\n",nnmxrevcelldepth);
+ printf("%f average shared lists\n",(double)nnrevshare/(double)nnrevcells);
+ printf("Took %f seconds\n",0.001 * (msec_time()-smsec));
+ printf("Overall took %f seconds\n",0.001 * (msec_time()-smsec));
}
-
- if (s->verbose)
- fprintf(stdout, "%cThere %s %d rev cache instance%s with %lu Mbytes limit\n",
- cr_char,
- g_no_rev_cache_instances > 1 ? "are" : "is",
- g_no_rev_cache_instances,
- g_no_rev_cache_instances > 1 ? "s" : "",
- (unsigned long)ram_portion/1000000);
+#endif
}
+
s->rev.rev_valid = 1;
-#ifdef DEBUG
- if (fdi > 1) printf("%d cells in rev nn list\n",cellinrevlist);
- if (fdi > 1) printf("%d fwd cells in rev nn list\n",fwdcells);
- if (cellinrevlist > 1) printf("Avg list size = %f\n",(double)fwdcells/cellinrevlist);
-#endif
+ if (fdi > 1 && s->verbose)
+ fprintf(stdout, "%cnnrev initialization done\n",cr_char);
DBG(("init_revaccell finished\n"));
}
@@ -6205,20 +11219,19 @@ rspl *s /* Pointer to rspl grid */
/* Free up the contents of rev.rev[] and rev.nnrev[] */
if (s->rev.rev != NULL) {
for (rpp = s->rev.rev; rpp < (s->rev.rev + s->rev.no); rpp++) {
- if ((rp = *rpp) != NULL && --rp[2] <= 0) {
- DECSZ(s, rp[0] * sizeof(int));
- free(*rpp);
- *rpp = NULL;
- }
+ if (*rpp != NULL)
+ free_indexlist(s, rpp);
}
}
if (s->rev.nnrev != NULL) {
+
+ /* Free up nn list sharelist records - this will free and set */
+ /* any shared lists to NULL */
+ free_sharelist(s);
+
for (rpp = s->rev.nnrev; rpp < (s->rev.nnrev + s->rev.no); rpp++) {
- if ((rp = *rpp) != NULL && --rp[2] <= 0) {
- DECSZ(s, rp[0] * sizeof(int));
- free(*rpp);
- *rpp = NULL;
- }
+ if (*rpp != NULL)
+ free_indexlist(s, rpp);
}
}
@@ -6253,6 +11266,274 @@ rspl *s /* Pointer to rspl grid */
s->rev.rev_valid = 0;
}
+#ifdef CHECK_NNLU
+/* ====================================================== */
+
+/* Used exautive searches to check that nn lookup found a good solution */
+static void check_nn(
+rspl *s,
+double *oval, /* Un-clipped output target value */
+co *cpp /* Clipped output space value in cpp[0].v[] */
+ /* nn solution in cpp[0].p[] */
+) {
+ int i, j; /* Index of fwd grid point */
+ int e, f, ee, ff;
+ int di = s->di;
+ int fdi = s->fdi;
+ int gno = s->g.no;
+ int good = 1;
+ int found = 0;
+ int printed = 0;
+
+ ECOUNT(gc, MXRI, di, 0, s->g.res, 0);/* coordinates */
+ float *gp; /* Pointer to grid data */
+ double iv[MXDI];
+ double ov[MXDO];
+ double chov[MXDO], de;
+
+ int bix = -1;
+ double bdist = 1e200;
+ double biv[MXDI];
+ double bov[MXDO];
+ int six = -1;
+ double sdist = 1e200;
+ double siv[MXDI];
+ double sov[MXDO];
+
+ double odelta;
+ double idelta;
+ double fsdelta;
+ double sodelta;
+ double sidelta;
+
+ s->rev.cknn_no++;
+
+ /* Compute the given solutions de */
+ de = sqrt(lchw_sq(s, oval, cpp[0].v));
+
+ /* Go through every fwd vertex looking for closest and 2nd closest */
+ EC_INIT(gc);
+ for (gp = s->g.a, i = 0; i < gno; gp += s->g.pss, i++) {
+ double dist;
+
+ if (s->limiten && gp[-1] > s->limitv) {
+ EC_INC(gc);
+ continue; /* Over the ink limit */
+ }
+
+ for (f = 0; f < fdi; f++)
+ ov[f] = gp[f];
+
+ dist = lchw_sq(s, oval, ov);
+
+ if (dist < bdist) {
+ six = bix;
+ bix = i;
+ for (e = 0; e < s->di; e++) {
+ siv[e] = biv[e];
+ biv[e] = s->g.l[e] + gc[e] * s->g.w[e];
+ }
+ for (f = 0; f < fdi; f++) {
+ sov[f] = bov[f];
+ bov[f] = ov[f];
+ }
+ sdist = bdist;
+ bdist = dist;
+
+ } else if (dist < sdist) {
+ six = i;
+ for (e = 0; e < s->di; e++)
+ siv[e] = s->g.l[e] + gc[e] * s->g.w[e];
+ for (f = 0; f < fdi; f++)
+ sov[f] = ov[f];
+ sdist = dist;
+
+ }
+ EC_INC(gc);
+ }
+
+ /* What is magnitude of target match ? */
+ odelta = sqrt(lchw_sq(s, bov, oval));
+
+ /* What is magnitude of solution match */
+ idelta = 0.0;
+ for (e = 0; e < s->di; e++) {
+ double tt = biv[e] - cpp[0].p[e];
+ idelta += tt * tt;
+ }
+ idelta = sqrt(idelta);
+
+ /* What is scale of solution from closest to 2nd closest ? */
+ fsdelta = 0.0;
+ for (e = 0; e < s->di; e++) {
+ double tt = biv[e] - siv[e];
+ fsdelta += tt * tt;
+ }
+ fsdelta = sqrt(fsdelta);
+
+ /* What is magnitude of target match to secondary ? */
+ sodelta = sqrt(lchw_sq(s, sov, oval));
+
+ /* What is magnitude of solution match to secondary ?*/
+ sidelta = 0.0;
+ for (e = 0; e < s->di; e++) {
+ double tt = siv[e] - cpp[0].p[e];
+ sidelta += tt * tt;
+ }
+ sidelta = sqrt(sidelta);
+
+ /* If our exaustive search is better than the nn solution: */
+ if (odelta < (de - 1e-6)) {
+ double dde = de - odelta;
+ if (dde > s->rev.cknn_we)
+ s->rev.cknn_we = dde;
+ s->rev.cknn_noerrs++;
+ good = 0;
+ printf("check_nn: target %s\n",debPdv(s->fdi,oval));
+ printf("check_nn: cliped to %s, de %f\n",debPdv(s->di,cpp[0].v),de);
+ printf("check_nn: solution %s\n",debPdv(s->di,cpp[0].p));
+ printf("check_nn: check target %s, de %f\n",debPdv(s->fdi, bov),odelta);
+ printf("check_nn: check solution %s, de %f @ix %d\n",debPdv(s->di, biv),idelta,bix);
+ printf("check_nn: check 2nd target %s, de %f\n",debPdv(s->fdi, sov),sodelta);
+ printf("check_nn: check 2nd solution %s, de %f @ ix %d\n",debPdv(s->di, siv),sidelta,six);
+ printf("check_nn: excess delta %f\n",dde);
+ printf("check_nn: first-second delta %f\n",fsdelta);
+ if (six >= 0 && (de - sodelta) > 1e-6) {
+ printf("check_nn: beyond 2nd best by %f!\n",de-sodelta);
+ s->rev.cknn_nobsb++;
+ }
+ printed = 1;
+ }
+
+ /* Search surface nnrev cells, to make sure our best is in it somewhere */
+ if (s->rev.surflist != NULL) {
+ bxcell *ss;
+
+ for (ss = s->rev.surflist; ss != NULL; ss = ss->slist) {
+ int *flist = ss->sl; /* List of fwd cells */
+
+ if (flist == NULL)
+ error("surflist nnrev[%d] is empty!",ss->ix);
+
+ /* For each forward cell */
+ for (flist += 3; *flist != -1; flist++) {
+ /* For each cube vertex */
+ for (ee = 0; ee < (1<<di); ee++) {
+ int vix = *flist + s->g.hi[ee];
+ if (vix == bix) {
+ found = 1;
+ if (!good)
+ printf("check_nn: found best vertex in surf nnrev[%d] fwd %d \n",ss->ix,*flist);
+ break;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ int rgno = s->rev.no;
+ int **rpp;
+ int revfound = 0;
+
+ s->rev.cknn_nonis++;
+ if (good) {
+ printf("check_nn: target %s\n",debPdv(s->fdi,oval));
+ printf("check_nn: cliped to %s, de %f\n",debPdv(s->di,cpp[0].v),de);
+ printf("check_nn: solution %s\n",debPdv(s->di,cpp[0].p));
+ printf("check_nn: check target %s, de %f\n",debPdv(s->fdi, bov),odelta);
+ printf("check_nn: check solution %s, de %f\n",debPdv(s->di, biv),idelta);
+ printf("check_nn: result is OK\n");
+ }
+ if (s->rev.surflist == NULL) {
+ printf("check_nn: No surface list to check against\n");
+ } else {
+ printf("check_nn: DIDN'T find best vertex %d in nnrev[] surface list\n",bix);
+ }
+ printed = 1;
+
+ /* See where it is in the rev[] list, and what the corresponding nnrev[] */
+ /* looks like */
+ for (rpp = s->rev.rev, i = 0; i < rgno; rpp++, i++) {
+ int *flist = *rpp;
+
+ if (flist == NULL)
+ continue;
+
+ /* For each forward cell */
+ for (flist += 3; *flist != -1; flist++) {
+ /* For each cube vertex */
+ for (ee = 0; ee < (1<<di); ee++) {
+ int vix = *flist + s->g.hi[ee];
+ if (vix == bix) {
+ revfound = 1;
+ printf("check_nn: found best vertex in rev[%d] fwd %d",i,*flist);
+ if (s->rev.nnrev[i] != NULL)
+ printf(" - cspndg. nnrev has list\n");
+ else
+ printf(" - cspndg. nnrev is empty\n");
+ break;
+ }
+ }
+ }
+ }
+ if (!revfound) {
+ printf("check_nn: DIDN'T find best vertex %d in rev list\n",bix);
+ }
+ }
+ }
+
+ /* Check if the nnrev[] cell for this target has the fwd cell */
+ if (s->rev.surflist != NULL && (!good || !found)) {
+ int mi[MXDO];
+ int rgres_1 = s->rev.res - 1;
+ int ix, *flist;
+ int found2 = 0;
+
+ for (ix = 0, f = 0; f < fdi; f++) {
+ double t = (oval[f] - s->rev.gl[f])/s->rev.gw[f];
+ mi[f] = (int)floor(t); /* Grid coordinate */
+ if (mi[f] < 0) /* Clip to reverse range, so we always return a result */
+ mi[f] = 0;
+ else if (mi[f] > rgres_1)
+ mi[f] = rgres_1;
+ ix += mi[f] * s->rev.coi[f]; /* Accumulate reverse grid index */
+ }
+ flist = s->rev.nnrev[ix];
+
+ if (flist != NULL) {
+ /* For each forward cell */
+ for (flist += 3; *flist != -1; flist++) {
+ /* For each cube vertex */
+ for (ee = 0; ee < (1<<di); ee++) {
+ int vix = *flist + s->g.hi[ee];
+ if (vix == bix) {
+ found2 = 1;
+ printf("check_nn: found best vertex %d in expected nnrev[%d], fwd %d\n",bix,ix,*flist);
+ printed = 1;
+ break;
+ }
+ }
+ }
+ }
+ if (!found2) {
+ printf("check_nn: DIDN'T find best vertex %d in expected nnrev[%d] list\n",bix,ix);
+ printed = 1;
+ }
+ }
+ if (printed)
+ printf("\n");
+}
+
+static void print_nnck(rspl *s) {
+ printf("check_nn di %d fdi %d checked %d lookups:\n",s->di,s->fdi,s->rev.cknn_no);
+ printf("check_nn got %d not as good as best vertex\n",s->rev.cknn_noerrs);
+ printf("check_nn got %d not as good as 2nd best vertex\n",s->rev.cknn_nobsb);
+ printf("check_nn got %d not in surface list\n",s->rev.cknn_nonis);
+ printf("check_nn got %f worst excess de\n",s->rev.cknn_we);
+ printf("\n");
+}
+
+#endif /* CHECK_NNLU */
/* ====================================================== */
/* Initialise the rev First section, basic information that doesn't change */
@@ -6265,8 +11546,7 @@ rspl *s
int di = s->di;
int fdi = s->fdi;
int rgno, gno = s->g.no;
- int argres; /* Allocation rgres, = no cells +1 */
- int rgres;
+ int rgres; /* bwd cell grid (rev[], nnrev[]) resolution */
int rgres_1; /* rgres -1 == maximum base coord value */
datao rgmin, rgmax;
@@ -6318,26 +11598,23 @@ rspl *s
if ((rgres = (int) gresmul * s->g.mres) < 4)
rgres = 4;
}
- argres = rgres+1;
- s->rev.ares = argres; /* == number of verticies per side, used for construction */
s->rev.res = rgres; /* == number of cells per side */
rgres_1 = rgres-1;
- /* Number of elements in the rev.grid, including construction extra rows */
- for (rgno = 1, f = 0; f < fdi; f++, rgno *= argres);
+ /* Number of elements in the rev.grid */
+ for (rgno = 1, f = 0; f < fdi; f++, rgno *= rgres);
s->rev.no = rgno;
-//printf("~1 argres = %d\n",argres);
+//printf("~1 rgres = %d\n",rgres);
/* Compute coordinate increments */
s->rev.coi[0] = 1;
//printf("~1 coi[0] = %d\n",s->rev.coi[0]);
for (f = 1; f < fdi; f++) {
- s->rev.coi[f] = s->rev.coi[f-1] * argres;
+ s->rev.coi[f] = s->rev.coi[f-1] * rgres;
//printf("~1 coi[%d] = %d\n",f,s->rev.coi[f]);
}
/* Compute index offsets from base of cube to other corners. */
-
for (s->rev.hoi[0] = f = 0, j = 1; f < fdi; j *= 2, f++) {
for (i = 0; i < j; i++)
s->rev.hoi[j+i] = s->rev.hoi[i] + s->rev.coi[f]; /* In grid points */
@@ -6361,7 +11638,6 @@ rspl *s
INCSZ(s, rgno * sizeof(int *));
s->rev.inited = 1;
-
s->rev.stouch = 1;
DBG(("make_rev_one finished\n"));
@@ -6370,7 +11646,7 @@ rspl *s
/* ====================================================== */
/* First section of rev_struct init. */
-/* Initialise the reverse cell cache, sub simplex information */
+/* Initialise the fxcell cache, sub simplex information */
/* and reverse lookup acceleration structures. */
/* This is called by a reverse interpolation call */
/* that discovers that the reverse index list haven't */
@@ -6563,8 +11839,8 @@ rspl *s
#if defined(DEBUG1) || defined(DEBUG2)
-/* Utility - return a string containing a cells output value range */
-static char *pcellorange(cell *c) {
+/* Utility - return a string containing a fwd cells output value range */
+static char *pcellorange(fxcell *c) {
static char buf[5][300];
static ix = 0;
char *bp;
@@ -6615,8 +11891,707 @@ static char *pcellorange(cell *c) {
#define DBGV(xxx)
#define DBG(xxx)
+#ifdef REVVRML
+/* ====================================================== */
+/* VRML diagnostic output functions */
+
+/* Plot the initial surface rev cells */
+static void plot_bxfwcells(
+rspl *s,
+int dobxcells, /* Plot rev cells */
+int dofwcells, /* Plot fwd cells */
+int dofwlabels /* Plot fwd cell base indexs */
+) {
+ int i, j; /* Index of fwd grid point */
+ int e, f, ee, ff;
+ int di = s->di;
+ int fdi = s->fdi;
+ bxcell *bx;
+ vrml *wrl;
+ double grey[3] = { 0.5, 0.5, 0.5 };
+ double white[3] = { 1.0, 1.0, 1.0 };
+
+ wrl = new_vrml("raw_bxfwcells", 0, vrml_lab);
+ wrl->add_marker(wrl, s->rev.ocent, NULL, 1.0);
+
+ if (dofwlabels) {
+ /* Put text for every base cube index */
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int vix[POW2MXRI];
+ int *crp, *rp;
+
+ crp = s->rev.rev[bx->ix];
+
+ for (rp = crp+3; *rp != -1; rp++) {
+ int ix = *rp;
+ char index[100];
+ double vv[MXRI];
+ int off = 0; // 0 .. 7, choose cube vertex
+ float *fcb = s->g.a + (ix + s->g.hi[off]) * s->g.pss;
+
+ for (e = 0; e < di; e++)
+ vv[e] = fcb[e];
+ sprintf(index, "%d",ix);
+ wrl->add_text(wrl, index, vv, white, 0.3);
+ }
+ }
+ }
+
+ if (dobxcells) {
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int vix[POW2MXRO];
+ DCOUNT(cc, MXRO, fdi, 0, 0, 2); /* Vertex counter */
+ int *crp, *rp;
+
+ /* Plot bxcell's */
+ i = 0;
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ double vv[MXRO];
+ for (f = 0; f < fdi; f++)
+ vv[f] = (bx->gc[f] + cc[f]) * s->rev.gw[f] + s->rev.gl[f];
+ vix[i] = wrl->add_vertex(wrl, 0, vv);
+ DC_INC(cc);
+ i++;
+ }
+
+ /* For each vertex */
+ for (i = 0; i < (1 << fdi); i++) {
+ int lix[2];
+
+ lix[0] = vix[i];
+
+ /* for each dimension */
+ for (j = 0; j < fdi; j++) {
+ if (i & (1<<j))
+ continue; /* Would go outside cube */
+
+ lix[1] = vix[i | (1 << j)];
+ if (dofwcells)
+ wrl->add_col_line(wrl, 0, lix, grey);
+ else
+ wrl->add_line(wrl, 0, lix);
+ }
+ }
+ }
+ }
+
+ if (dofwcells) {
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int vix[POW2MXRI];
+ int *crp, *rp;
+
+ /* Add fwd cells */
+ crp = s->rev.rev[bx->ix];
+ for (rp = crp+3; *rp != -1; rp++) {
+ float *fcb = s->g.a + *rp * s->g.pss;
+
+ /* Skip grid base points on the upper edge of the grid */
+ for (e = 0; e < di; e++) {
+ if (G_FL(fcb, e) == 0) /* At the top edge */
+ break;
+ }
+ if (e < di) {
+ printf("Fwd cell base index %d is on upper edge!\n",*rp);
+ continue;
+ }
+
+ /* For each vertex of cube */
+ for (i = 0; i < (1<<di); i++) {
+ double vv[MXRI];
+ int ix = *rp + s->g.hi[i];
+ fcb = s->g.a + ix * s->g.pss;
+
+ if (!s->limiten || fcb[-1] <= s->limitv)
+ break;
+ }
+ /* Skip any cubes that a completely over the ink limit */
+ if (i >= (1<<di))
+ continue;
+
+ /* For each vertex of cube */
+ for (i = 0; i < (1<<di); i++) {
+ double vv[MXRI];
+ int ix = *rp + s->g.hi[i];
+ fcb = s->g.a + ix * s->g.pss;
+
+ for (e = 0; e < di; e++)
+ vv[e] = fcb[e];
+ vix[i] = wrl->add_vertex(wrl, 1, vv);
+ }
+
+ /* For each vertex of cube */
+ for (i = 0; i < (1<<di); i++) {
+ int lix[2];
+
+ lix[0] = vix[i];
+
+ /* for each dimension */
+ for (j = 0; j < di; j++) {
+ if (i & (1<<j))
+ continue; /* Would go outside cube */
+
+ lix[1] = vix[i | (1 << j)];
+ wrl->add_line(wrl, 1, lix);
+ }
+ }
+ }
+ }
+ }
+ wrl->make_lines_vc(wrl, 0, 0.0);
+ wrl->make_lines_vc(wrl, 1, 0.0);
+
+ printf("Created %s\n",wrl->name);
+ wrl->del(wrl);
+}
+
+/* Plot vertex & triangle check setup & solution */
+/* + the primary and shadow bxcells. */
+static void plot_tri_check(
+rspl *s,
+int dobxcells, /* Plot prim & shadow bxcell cells */
+int dowait, /* Wait for the user to hit return */
+bxcell *bx, /* First bx cell (if dobxcells set) */
+int vtxix, /* triangle base vertex index (-1 if not applicable) */
+int trii, /* Triangle eneration */
+int triix[3], /* Triangle indexes */
+int nvtxix, /* test point vertex index number (may be -1 if not vtxrec) */
+int sorv, /* Intersection was solved ? */
+int wsrv, /* Within simplex ? */
+int shdwd, /* Vertex is shadowed ? */
+double v[MXRI+1][MXRO], /* Triangle vertex values */
+double de[MXRO], /* Line delta */
+double pv[MXRO], /* Vertex being tested */
+double xv[MXRO] /* Intersection point */
+) {
+ int j;
+ int e, f, ee, ff;
+ int di = s->di;
+ int fdi = s->fdi;
+ vrml *wrl;
+ bxcell *vbx;
+ int first = 1;
+ int ii, vix[POW2MXRO], lix[3];
+ double vv[MXRO];
+ double white[3] = { 1.0, 1.0, 1.0 };
+ double grey[3] = { 0.5, 0.5, 0.5 };
+ double green[3] = { 0.1, 1.0, 0.1 };
+ double red[3] = { 0.8, 0.1, 0.1 };
+ double blue[3] = { 0.1, 0.1, 0.8 };
+ double yellow[3] = { 0.8, 0.8, 0.1 };
+
+ wrl = new_vrml("tri_check", 0, vrml_lab);
+
+ /* Gamut center point marker */
+ wrl->add_marker(wrl, s->rev.ocent, NULL, 1.0);
+
+ /* point being tested marker */
+ wrl->add_marker(wrl, pv, shdwd ? red : blue, 0.5);
+
+ /* Intersection point */
+ if (wsrv)
+ wrl->add_marker(wrl, xv, blue, 0.2);
+
+ /* Line from center through point being tested */
+ lix[0] = wrl->add_vertex(wrl, 0, s->rev.ocent);
+ for (ii = 0; ii < fdi; ii++)
+ vv[ii] = s->rev.ocent[ii] + 10.0 * de[ii];
+ lix[1] = wrl->add_vertex(wrl, 0, vv);
+ wrl->add_col_line(wrl, 0, lix, grey);
+
+ /* Triangle */
+ lix[0] = wrl->add_vertex(wrl, 1, v[0]);
+ lix[1] = wrl->add_vertex(wrl, 1, v[1]);
+ lix[2] = wrl->add_vertex(wrl, 1, v[2]);
+ wrl->add_col_triangle(wrl, 1, lix, green);
+ /* And again to get both faces */
+ lix[0] = wrl->add_vertex(wrl, 1, v[0]);
+ lix[1] = wrl->add_vertex(wrl, 1, v[2]);
+ lix[2] = wrl->add_vertex(wrl, 1, v[1]);
+ wrl->add_col_triangle(wrl, 1, lix, green);
+
+ if (dobxcells) {
+//printf(" bx = %p\n",bx);
+ for (vbx = bx; vbx != NULL; vbx = vbx->wlist) {
+ DCOUNT(cc, MXRO, fdi, 0, 0, 2); /* Vertex counter */
+ int *crp, *rp;
+
+//printf(" vrml adding bxcell %d\n",vbx->ix);
+ /* Plot bxcell's */
+ ii = 0;
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ for (f = 0; f < fdi; f++)
+ vv[f] = (vbx->gc[f] + cc[f]) * s->rev.gw[f] + s->rev.gl[f];
+//printf(" vrml vtx %d from %s\n",vix[i], debPdv(3,vv));
+ vix[ii] = wrl->add_vertex(wrl, 0, vv);
+ DC_INC(cc);
+ ii++;
+ }
+
+ /* For each vertex */
+ for (ii = 0; ii < (1 << fdi); ii++) {
+
+ lix[0] = vix[ii];
+
+ /* for each dimension */
+ for (j = 0; j < fdi; j++) {
+ if (ii & (1<<j))
+ continue; /* Would go outside cube */
+
+ lix[1] = vix[ii | (1 << j)];
+//printf(" vrml line from vtx %d - %d\n",lix[0],lix[1]);
+ wrl->add_col_line(wrl, 0, lix, first ? white : red);
+ }
+ }
+ first = 0;
+ }
+ }
+
+ wrl->make_lines_vc(wrl, 0, 0.0);
+ wrl->make_triangles(wrl, 1, 0.0, NULL);
+ printf("Created %s\n",wrl->name);
+ wrl->del(wrl);
+
+ printf(" Solved %s, Within triang %s, shadowed %s\n", sorv ? "true" : "false", wsrv ? "true" : "false", shdwd ? "true" : "false");
+ printf("Testing against tri %d %d %d\n", triix[0], triix[1], triix[2]);
+
+ printf(" bx %d vtx %d tri %d checking nvx %d, hit return key:\n",bx->ix, vtxix, trii, nvtxix);
+ if (dowait) {
+ printf(" hit return key to continue:\n");
+ getchar();
+ }
+}
+
+/* Main summary plot at each thinning round and at end. */
+/* Show vertex surface & optional added or deleted vertexes, */
+/* + optional bxcells. */
+static void plot_vtx_surface(
+rspl *s,
+int dovtxlabels, /* Show vertex index numbers */
+int dodeleted, /* Show deleted vertexes */
+int doadded, /* Show added vertexes */
+int dopres, /* Show preserved vertexes */
+int dooil, /* Show over ink limit vertexes */
+int dobxcells, /* Show bxcells */
+int dowait, /* Wait for a return key */
+vtxcache *vc, /* Vertexes */
+assdire *edgdir /* Edge lookup for vertex */
+) {
+ vtxrec *vx, *nvx;
+ int i, j;
+ int f, fdi = s->fdi;
+ vrml *wrl;
+ double grey[3] = { 0.5, 0.5, 0.5 };
+ double red[3] = { 0.8, 0.1, 0.1 };
+ double green[3] = { 0.2, 0.8, 0.2 };
+ double blue[3] = { 0.2, 0.2, 0.8 };
+ double white[3] = { 0.8, 0.8, 0.8 };
+ double magenta[3] = { 0.8, 0.2, 0.8 };
+ double cyan[3] = { 0.0, 1.0, 1.0 };
+ double yellow[3] = { 1.0, 1.0, 0.0 };
+ bxcell *vbx;
+
+ if (dopres)
+ wrl = new_vrml("final_surface", 0, vrml_lab);
+ else
+ wrl = new_vrml("thinned_surface", 0, vrml_lab);
+ wrl->add_marker(wrl, s->rev.ocent, NULL, 1.0);
+
+ if (dovtxlabels) {
+ for (i = 0; i < vc->hash_size; i++) {
+ for (vx = vc->hash[i]; vx != NULL; vx = vx->hlink) {
+ char index[100];
+
+ if (vx->status == vtx_norm
+ || (dodeleted && (vx->status == vtx_sha || vx->status == vtx_del))
+ || (doadded && vx->addvtx)
+ || (dopres && vx->pres)
+ || (dooil && vx->status == vtx_oil)) {
+ sprintf(index, "%d",vx->ix);
+ wrl->add_text(wrl, index, vx->v, cyan, 0.3);
+ }
+ }
+ }
+ }
+
+ /* Go through the vertex hash to set every vertex value */
+ for (i = 0; i < vc->hash_size; i++) {
+ for (vx = vc->hash[i]; vx != NULL; vx = vx->hlink) {
+
+ if (vx->status != vtx_norm && vx->addvtx)
+ error ("Found vertex that is both deleted and cause of added bxcell");
+
+ if (doadded && vx->addvtx) /* Cause of added bxcell */
+ vx->vrmlix = wrl->add_col_vertex(wrl, 0, vx->v, green);
+ else if (dopres && vx->pres) /* Preserved vertex */
+ vx->vrmlix = wrl->add_col_vertex(wrl, 0, vx->v, yellow);
+ else if (dodeleted && (vx->status == vtx_sha || vx->status == vtx_del))
+ vx->vrmlix = wrl->add_col_vertex(wrl, 0, vx->v, red);
+ else if (dooil && vx->status == vtx_oil)
+ vx->vrmlix = wrl->add_col_vertex(wrl, 0, vx->v, blue);
+ else if (vx->status == vtx_norm)
+ vx->vrmlix = wrl->add_col_vertex(wrl, 0, vx->v, white);
+ }
+ }
+
+ /* Go through them again to get every line they are part of */
+ for (i = 0; i < vc->hash_size; i++) {
+ for (vx = vc->hash[i]; vx != NULL; vx = vx->hlink) {
+ assdire *edg; /* Edge table */
+ float *fp;
+ int fl;
+ int pline = 0; /* Plotted at least 1 line */
+ int lix[2];
+
+ fp = s->g.a + vx->ix * s->g.pss; /* This vertex in fwd grid */
+ fl = FLV(fp); /* Edge flags for this vertex */
+ edg = edgdir + fl;
+
+ /* For all possible edges that use this vertex */
+ for (j = 0; j < edgdir[fl].no; j++) {
+ int fix;
+ int eix;
+
+ /* Index of first vertex of the line */
+ fix = vx->ix + edg->ti[j].goffs[0];
+
+ /* Index number of vertex other than the one we got it from */
+ if (edg->ti[j].goffs[0] != 0)
+ eix = vx->ix + edg->ti[j].goffs[0];
+ else
+ eix = vx->ix + edg->ti[j].goffs[1];
+
+ if ((nvx = get_vtxrec(vc, eix)) != NULL) {
+ if ( (vx->status == vtx_norm
+ || (dodeleted && (vx->status == vtx_sha || vx->status == vtx_del))
+ || (doadded && vx->addvtx)
+ || (dopres && vx->pres)
+ || (dooil && vx->status == vtx_oil))
+ && (nvx->status == vtx_norm
+ || (dodeleted && (nvx->status == vtx_sha || nvx->status == vtx_del))
+ || (doadded && nvx->addvtx)
+ || (dopres && nvx->pres)
+ || (dooil && nvx->status == vtx_oil))) {
+
+ pline = 1; /* Will/would plot this */
+
+ /* Only plot the line once though */
+ if (fix == vx->ix) {
+ lix[0] = vx->vrmlix;
+ lix[1] = nvx->vrmlix;
+ wrl->add_line(wrl, 0, lix);
+ }
+ }
+ }
+ }
+
+ /* we have an orphan vertex */
+ if (pline == 0
+ && (dodeleted || vx->status == vtx_norm)
+ && (doadded || !vx->addvtx)) {
+ double vv[MXRO], off = 0.15, *col;
+
+ if (doadded && vx->addvtx) /* Cause of added bxcell */
+ col = green;
+ else if (dopres && vx->pres) /* Preserved vertex */
+ col = yellow;
+ else if (dodeleted && vx->status != vtx_norm)
+ col = red;
+ else if (dooil && vx->status == vtx_oil)
+ col = blue;
+ else if (vx->status == vtx_norm)
+ col = white;
+
+ for (f = 0; f < fdi; f++)
+ vv[f] = vx->v[f] + off;
+ lix[0] = wrl->add_vertex(wrl, 2, vv);
+ for (f = 0; f < fdi; f++)
+ vv[f] = vx->v[f] - off;
+ lix[1] = wrl->add_vertex(wrl, 2, vv);
+ wrl->add_col_line(wrl, 2, lix, col);
+
+ for (f = 0; f < fdi; f++)
+ vv[f] = vx->v[f] + ((f & 1) ? off : -off);
+ lix[0] = wrl->add_vertex(wrl, 2, vv);
+ for (f = 0; f < fdi; f++)
+ vv[f] = vx->v[f] - ((f & 1) ? off : -off);
+ lix[1] = wrl->add_vertex(wrl, 2, vv);
+ wrl->add_col_line(wrl, 2, lix, col);
+
+ for (f = 0; f < fdi; f++)
+ vv[f] = vx->v[f] + ((f & 2) ? off : -off);
+ lix[0] = wrl->add_vertex(wrl, 2, vv);
+ for (f = 0; f < fdi; f++)
+ vv[f] = vx->v[f] - ((f & 2) ? off : -off);
+ lix[1] = wrl->add_vertex(wrl, 2, vv);
+ wrl->add_col_line(wrl, 2, lix, col);
+ }
+ }
+ }
+ wrl->make_lines_vc(wrl, 0, 0.0);
+ wrl->make_lines_vc(wrl, 2, 0.0);
+
+ /* Plot surface cells */
+ if (dobxcells) {
+ for (vbx = s->rev.surflist; vbx != NULL; vbx = vbx->slist) {
+ DCOUNT(cc, MXRO, fdi, 0, 0, 2); /* Vertex counter */
+ int *crp, *rp, ii;
+ double vv[MXRO];
+ int vix[POW2MXRO], lix[2];
+
+ ii = 0;
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ for (f = 0; f < fdi; f++) {
+ vv[f] = (vbx->gc[f] + cc[f]) * s->rev.gw[f] + s->rev.gl[f];
+ vv[f] += d_rand(-0.05, 0.05);
+ }
+ vix[ii] = wrl->add_vertex(wrl, 1, vv);
+ DC_INC(cc);
+ ii++;
+ }
+
+ for (ii = 0; ii < (1 << fdi); ii++) {
+ lix[0] = vix[ii];
+
+ /* for each dimension */
+ for (j = 0; j < fdi; j++) {
+ if (ii & (1<<j))
+ continue; /* Would go outside cube */
+
+ lix[1] = vix[ii | (1 << j)];
+ if (vbx->debug) { /* Added bxcell */
+ wrl->add_col_line(wrl, 1, lix, magenta);
+ } else { /* Existing bxcell */
+ wrl->add_col_line(wrl, 1, lix, grey);
+ }
+ }
+ }
+ }
+ wrl->make_lines_vc(wrl, 1, 0.0);
+ }
+
+ printf("Created %s\n",wrl->name);
+ wrl->del(wrl);
+ if (dowait) {
+ printf(" Thinned vertexes surface: Hit return to continue\n");
+ getchar();
+ }
+}
+
+/* Plot bxcells touched by added cell */
+static void plot_touched_bxcells(
+rspl *s,
+int bxix /* Index of bx cell causing touches */
+) {
+ int j, f, fdi = s->fdi;
+ vrml *wrl;
+ bxcell *vbx;
+ int first = 1;
+ int ii, vix[POW2MXRO], lix[3];
+ double vv[MXRO];
+ double green[3] = { 0.1, 0.6, 0.1 };
+ double white[3] = { 1.0, 1.0, 1.0 };
+ double red[3] = { 0.8, 0.1, 0.1 };
+
+ wrl = new_vrml("add_touch_bxcells", 0, vrml_lab);
+
+ /* Gamut center point marker */
+ wrl->add_marker(wrl, s->rev.ocent, NULL, 1.0);
+
+ for (vbx = s->rev.surflist; vbx != NULL; vbx = vbx->slist) {
+ DCOUNT(cc, MXRO, fdi, 0, 0, 2); /* Vertex counter */
+ int *crp, *rp;
+
+ /* Plot bxcell's */
+ ii = 0;
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ for (f = 0; f < fdi; f++) {
+ vv[f] = (vbx->gc[f] + cc[f]) * s->rev.gw[f] + s->rev.gl[f];
+ if (vbx->debug == 2)
+ vv[f] += 0.05;
+ else if (vbx->debug == 1)
+ vv[f] -= 0.05;
+ }
+ vix[ii] = wrl->add_vertex(wrl, 0, vv);
+ DC_INC(cc);
+ ii++;
+ }
+ /* For each vertex */
+ for (ii = 0; ii < (1 << fdi); ii++) {
+
+ lix[0] = vix[ii];
+
+ /* for each dimension */
+ for (j = 0; j < fdi; j++) {
+ if (ii & (1<<j))
+ continue; /* Would go outside cube */
+
+ lix[1] = vix[ii | (1 << j)];
+ wrl->add_col_line(wrl, 0, lix,
+ vbx->debug == 2 ? white : vbx->debug == 1 ? red : green);
+ }
+ }
+ }
+
+ wrl->make_lines_vc(wrl, 0, 0.0);
+ printf("Created %s\n",wrl->name);
+ wrl->del(wrl);
+
+ printf(" Touched bx cells for bx %d: Hit return to continue\n",bxix);
+ getchar();
+}
+
+/* Plot the thinned surface fwd cells */
+static void plot_fxcell_surface(
+rspl *s,
+int dofclabels, /* Show fwd cell base indexes */
+int dobxcells, /* Show bxcells */
+int dowait /* Wait for a return key */
+) {
+ bxcell *bx;
+ int i, j;
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+ vrml *wrl;
+ double grey[3] = { 0.5, 0.5, 0.5 };
+ double white[3] = { 1.0, 1.0, 1.0 };
+
+ wrl = new_vrml("thinned_fwcells", 0, vrml_lab);
+ wrl->add_marker(wrl, s->rev.ocent, NULL, 1.0);
+
+ if (dofclabels) {
+ /* Put text for every base cube index */
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ int vix[POW2MXRI];
+ int *crp, *rp;
+
+ crp = bx->sl;
+
+ for (rp = crp+3; *rp != -1; rp++) {
+ int ix = *rp;
+ char index[100];
+ double vv[MXRI];
+ int off = 0; // 0 .. 7, choose cube vertex
+ float *fcb = s->g.a + (ix + s->g.hi[off]) * s->g.pss;
+
+ for (e = 0; e < di; e++)
+ vv[e] = fcb[e];
+ sprintf(index, "%d",ix + s->g.hi[off]);
+ wrl->add_text(wrl, index, vv, white, 0.3);
+ }
+ }
+ }
+
+ for (bx = s->rev.surflist; bx != NULL; bx = bx->slist) {
+ DCOUNT(cc, MXRO, fdi, 0, 0, 2); /* Vertex counter */
+ int vix[POW2MXRI];
+ int *crp, *rp;
+
+ if (dobxcells) {
+ /* Plot bxcell's */
+ i = 0;
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ double vv[MXRO];
+ for (f = 0; f < fdi; f++)
+ vv[f] = (bx->gc[f] + cc[f]) * s->rev.gw[f] + s->rev.gl[f];
+ vix[i] = wrl->add_vertex(wrl, 1, vv);
+ DC_INC(cc);
+ i++;
+ }
+
+ /* For each vertex */
+ for (i = 0; i < (1 << fdi); i++) {
+ int lix[2];
+
+ lix[0] = vix[i];
+
+ /* for each dimension */
+ for (j = 0; j < fdi; j++) {
+ if (i & (1<<j))
+ continue; /* Would go outside cube */
+
+ lix[1] = vix[i | (1 << j)];
+ wrl->add_col_line(wrl, 1, lix, white);
+ }
+ }
+ }
+
+ crp = bx->sl;
+
+ for (rp = crp+3; *rp != -1; rp++) {
+ float *fcb = s->g.a + *rp * s->g.pss;
+
+ /* Skip grid base points on the upper edge of the grid */
+ for (e = 0; e < di; e++) {
+ if (G_FL(fcb, e) == 0) /* At the top edge */
+ break;
+ }
+ if (e < di) {
+ printf("Fwd cell base index %d is on upper edge!\n",*rp);
+ continue;
+ }
+
+ /* For each vertex of cube */
+ for (i = 0; i < (1<<di); i++) {
+ double vv[MXRI];
+ int ix = *rp + s->g.hi[i];
+ float *fcb = s->g.a + ix * s->g.pss;
+
+ if (!s->limiten || fcb[-1] <= s->limitv)
+ break;
+ }
+ /* Skip any cubes that a completely over the ink limit */
+ if (i >= (1<<di))
+ continue;
+
+ /* For each vertex of cube */
+ for (i = 0; i < (1<<di); i++) {
+ double vv[MXRI];
+ int ix = *rp + s->g.hi[i];
+ float *fcb = s->g.a + ix * s->g.pss;
+
+ for (e = 0; e < di; e++)
+ vv[e] = fcb[e];
+ vix[i] = wrl->add_vertex(wrl, 0, vv);
+ }
+
+ /* For each vertex of cube */
+ for (i = 0; i < (1<<di); i++) {
+ int lix[2];
+
+ lix[0] = vix[i];
+
+ /* for each dimension */
+ for (j = 0; j < di; j++) {
+ if (i & (1<<j))
+ continue; /* Would go outside cube */
+
+ lix[1] = vix[i | (1<<j)];
+ wrl->add_line(wrl, 0, lix);
+ }
+ }
+ }
+ }
+ if (dobxcells)
+ wrl->make_lines_vc(wrl, 1, 0.0);
+ wrl->make_lines_vc(wrl, 0, 0.0);
+ printf("Created %s\n",wrl->name);
+ wrl->del(wrl);
+
+ if (dowait) {
+ printf(" Thinned fwd cell surface: Hit return to continue\n");
+ getchar();
+ }
+}
+
+/* ====================================================== */
+#endif /* REVVRML */
diff --git a/rspl/rev.h b/rspl/rev.h
index b947cbe..6fc79cb 100644
--- a/rspl/rev.h
+++ b/rspl/rev.h
@@ -37,21 +37,22 @@
* with a cartesian coordinate, but the parameter order corresponds with
* the baricentric order.
*
- * For example, given cartesian coordinates D0, D1, D2
- * these should be sorted from smallest to largest, thereby
- * choosing a particular simplex within a cube, and allowing
- * a correspondence to the parameter coordinates, ie:
+ * For example, given cartesian sub-coordinates D0, D1, D2
+ * into a (3D) forward interpolation cube, these should be sorted
+ * from smallest to largest, thereby choosing a particular
+ * simplex within a cube, and allowing a correspondence to
+ * the parameter coordinates, ie:
*
- * D1 D0 D2 Smallest -> Largest cartesian sort
- * P2 P1 P0 Corresponding Parameter coordinates (note reverse order!)
+ * D2 D0 D1 Smallest -> Largest cartesian sort
+ * P0 P1 P2 Corresponding Parameter coordinates
*
- * B0 = P0 Conversion to Baricentric coordinates
+ * B0 = P0 Conversion to Baricentric weighting/coordinates
* B1 = P1 - P0
* B2 = P2 - P1
* B3 = 1 - P2
*
- * The vertex values directly correspond to Baricentric coordinates,
- * giving the usual interpolation equation of:
+ * The 4 (tetrahedron) vertex values directly correspond to Baricentric
+ * weighting/coordinates, giving the usual interpolation equation of:
*
* VV0 * B0
* + VV1 * B1
@@ -66,21 +67,42 @@
* + VV2 - VV3 * P2
* + VV3
*
+ * Note that withing the simplex, 0 <= P0 && P0 <= P1 && P1 <= P2 && P2 <= 1
+ *
* It is this which is used in rev.c for solving the reverse
* interpolation problem.
*/
-/* A structure to hold per simplex coordinate and vertex mapping */
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Group size information for nn LCh weighted quick accept/reject testing */
+typedef struct {
+ double bcent[MXRO]; /* Group center location in output space */
+ double brad; /* Output value bounding shere radius */
+ double bradsq; /* Output value bounding shere radius squared */
+
+ double maxDlc; /* Maximum members weighted delta LC (+extra dims) squared */
+ double maxDh; /* Maximum members delta h squared */
+ double maxDh_; /* Maximum members delta h (not squared) */
+ double sratio; /* Minimum members C ratio to Gc squared */
+ double bratio; /* Maximum members C ratio to Gc squared */
+ double Wsratio; /* Minimum members C ratio to Gc squared - pre-weighted */
+ double Wbratio; /* Maximum members C ratio to Gc squared - pre-weighted */
+ double Gc; /* Group center Chrominance squared */
+ double Gc_; /* Group center Chrominance (not squared) */
+} nn_grp;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* A structure to hold per simplex coordinate and vertex mapping for ssxinfo. */
/* This is relative to the construction cube. A face sub-simplex */
/* that is common between cubes, will have a different psxinfo */
/* depending on which cube created it. */
typedef struct {
int face; /* Flag, nz if simplex lies on cube surface */
- int icomb[MXDI]; /* Index by Absolute[di] -> Simplex Parameter[sdi], */
+ int icomb[MXDI]; /* icomb[] specifies the equation to convert simplex space */
+ /* coordinates back into cartesian space. */
+ /* Index by Absolute[di] -> Simplex Parameter[sdi], */
/* -1 == value 0, -2 == value 1 */
/* Note that many Abs can map to one Param to form a sum. */
- /* icomb[] specifies the equation to convert simplex space */
- /* coordinates back into cartesian space. */
int offs[MXDI+1]; /* Offsets to simplex verticies within cube == bit per dim */
int goffs[MXDI+1]; /* Offsets to simplex verticies within grid */
int foffs[MXDI+1]; /* Fwd grid floating offsets to simplex verticies from cube base */
@@ -97,9 +119,9 @@ typedef struct {
/* - - - - - - - - - - - - - - - - - - - - - */
/* NOTE :- This should really be re-arranged to be per-sub-simplex caching, */
-/* rather than cell caching. Rather than stash the simplex info in the cells, */
+/* rather than fxcell caching. Rather than stash the simplex info in the fxcells, */
/* create a separate cache or some other way of sharing the common simplexes. */
-/* The code that ignores common face simplexes in cells could then be removed. */
+/* The code that ignores common face simplexes in fxcells could then be removed (?). */
/* Simplex definition. Each top level fwd interpolation cell, */
/* is decomposed into sub-simplexes. Sub-simplexes are of equal or */
@@ -111,12 +133,12 @@ struct _simplex {
int si; /* Diagnostic - simplex number within level */
int sdi; /* Sub-simplex dimensionality */
int efdi; /* Effective fdi. This will be = fdi for a non clip */
- /* plane simplex, and fdi+1 for a clip plane simplex */
- /* The DOF (Degress of freedom) withing this simplex = sdi - efdi */
+ /* plane simplex, and fdi+1 for a clip plane simplex. */
+ /* The DOF (Degress of freedom) within this simplex = sdi - efdi */
psxinfo *psxi; /* Generic per simplex info (construction cube relative) */
int vix[MXRI+1]; /* fwd cell vertex indexes of this simplex [sdi+1] */
- /* This is a universal identification of this simplex */
+ /* This is a universal identification of this simplex. */
struct _simplex *hlink; /* Link to other cells with this hash */
unsigned int touch; /* Last touch count. */
short flags; /* Various flags */
@@ -130,7 +152,6 @@ struct _simplex {
#define SPLX_FLAG_5 0x40 /* auxiliary lu/svd initialised */
#define SPLX_FLAG_5F 0x80 /* auxiliary lu/svd init. failed */
-
#define SPLX_FLAGS (SPLX_FLAG_1 | SPLX_FLAG_2 | SPLX_FLAG_2F \
| SPLX_FLAG_4 | SPLX_FLAG_5 | SPLX_FLAG_5F)
@@ -151,7 +172,7 @@ struct _simplex {
double min[MXRO+1], max[MXRO+1]; /* Simplex vertex output space [fdi+1] and */
/* ink limit bounding values at minmax[fdi] */
- /* If sdi == efdi, this holds the LU decomposition */
+ /* If sdi == efdi, this holds the LU decomposition, */
/* else this holds the SVD and solution locus info */
char *aloc2; /* Memory allocation for #2 & #4 */
@@ -187,27 +208,31 @@ struct _simplex {
}; typedef struct _simplex simplex;
-/* A candidate search cell (cell cache entry structure) */
-struct _cell {
+/* A candidate search (fwd) fxcell (cell cache entry structure) */
+struct _fxcell {
struct _rspl *s; /* Pointer to parent rspl */
/* Cache information */
- int ix; /* Fwd cell index */
- struct _cell *hlink; /* Link to other cells with this hash */
- struct _cell *mrudown; /* Links to next most recently used cell */
- struct _cell *mruup;
+ int ix; /* Corresponding fwd cell index */
+ struct _fxcell *hlink; /* Link to other cells with this hash */
+ struct _fxcell *mrudown;/* Links to next most recently used fxcell */
+ struct _fxcell *mruup;
int refcount; /* Reference count */
- int flags; /* Non-zero if the cell has been initialised */
-#define CELL_FLAG_1 0x01 /* Basic initialisation */
+ int flags; /* Non-zero if the fxcell has been initialised */
+#define CELL_FLAG_1 0x01 /* Basic initialisation, including nn_grp */
#define CELL_FLAG_2 0x02 /* Simplex information initialised */
/* Use information */
double sort; /* Sort key */
+ double limmin, limmax; /* limit() min/max for this fxcell */
- double limmin, limmax; /* limit() min/max for this cell */
- double bcent[MXRO]; /* Output value bounding shere center */
- double brad; /* Output value bounding shere radius */
- double bradsq; /* Output value bounding shere radius squared */
+ /* Quick nn distance information */
+ nn_grp g;
+
+// double bcent[MXRO]; /* Output value bounding shere center */
+// double brad; /* Output value bounding shere radius */
+// double bradsq; /* Output value bounding shere radius squared */
+// double wbrad; /* Output value weighted bounding shere radius */
double p[POW2MXRI][MXRI]; /* Vertex input positions for this cube. */
/* Copied to x->pmin/pmax[] & ink limit */
@@ -215,18 +240,61 @@ struct _cell {
double v[POW2MXRI][MXRO+1]; /* Vertex data for this cube. Copied to x->v[] */
/* v[][fdi] is the ink limit values, if relevant */
- simplex **sx[MXRI+1]; /* Lists of simplexes that make up this cell. */
+ simplex **sx[MXRI+1]; /* Lists of simplexes that make up this fxcell. */
/* Each list indexed by the non-limited simplex */
/* dimensionality (similar to sspxi[]) */
/* Each list will be NULL if it hasn't been created yet */
int sxno[MXRI+1]; /* Corresponding count of each list */
-}; typedef struct _cell cell;
+}; typedef struct _fxcell fxcell;
+
+/* surface bxcell sl status */
+typedef enum {
+ bx_uninit = 0, /* sl is not initialised */
+ bx_filled = 1, /* sl has been filled with initial fwd cell vertexes */
+ bx_rethinnd = 2, /* sl vertexes need to be re-thinned */
+ bx_thinned = 3, /* sl vertexes have been thinned */
+ bx_conv = 4 /* sl vertexes have been converted to fwd cell indexes */
+} bxstat;
+
+/* Structure to hold bwd cell information for surface list, and also */
+/* for seed fill bwd cell propogation. (Cells on surface will have two */
+/* of these) */
+struct _bxcell{
+ int ix; /* nnrev[] index of this bwd cell */
+ int gc[MXRO]; /* coordinate of this bwd cell */
+ nn_grp g; /* Group nn calculation info */
+ struct _bxcell *ss; /* bwd surface cell to start search from */
+ double sdist; /* Est. wtd distance from this cell to ss */
+ int tix; /* target rev[] index being filled (visited check) */
+
+ bxstat status; /* State of sl list */
+ int *sl; /* fwd vertex seed list for surface bxcells */
+ int *dl; /* deleted fwd vertex list for this bxcell */
+
+ int *scell; /* If non-NULL, this is a (non-surface) */
+ /* seeding super bxcell, and scell contains */
+ /* the list of bxcells covered */
+
+ struct _bxcell *slist; /* Linked list of all surface bxcells */
+ struct _bxcell *hlink; /* Linked list of surface bxcells with same ix hash */
+ struct _bxcell *xlist; /* Linked list of surface exploration search region */
+ double emin; /* estimated minimum wtd distance of this cell in current search */
+ struct _bxcell *tlist; /* Linked list of solution surface cells for current search. */
+
+ struct _bxcell *flist; /* Linked list for nnrev[] fill seeds */
+
+ double cc; /* Distance of group from gamut center */
+ double dw; /* Delta width from ocent of furthest point */
+ struct _bxcell *wlist; /* Linked list for shadow bxcells during thinning */
+
+ int debug; /* debug flag - for VRML tagging */
+}; typedef struct _bxcell bxcell;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/* Enough space is needed to cache all the cells/simplexes */
+/* Enough space is needed to cache all the fxcells/simplexes */
/* for a full aux. locus, or the query will be processed in */
/* several "chunks" and will be slower. */
/* This sets the basic memory usage of the rev code. */
@@ -239,20 +307,20 @@ struct _cell {
/* rev as a fraction of the System RAM. */
#define HASH_FILL_RATIO 3 /* 3 Ratio of entries to hash size */
-/* The structure where cells are allocated and cached. */
+/* The structure where fxcells and simplexes are allocated and cached. */
-/* Holds the cell and simplex match cache specific information */
+/* Holds the fxcell and simplex match cache specific information */
typedef struct {
struct _rspl *s; /* Pointer to parent rspl */
int nacells; /* Number of allocated cells */
int nunlocked; /* Number of unlocked cells that could be freed */
int cell_hash_size; /* Current size of cell hash list */
- cell **hashtop; /* Top of hash list [cell_hash_size] */
- cell *mrutop, *mrubot; /* Top and bottom pointers of mru list */
- /* that tracks allocated cells */
+ fxcell **hashtop; /* Top of hash list [cell_hash_size] */
+ fxcell *mrutop, *mrubot; /* Top and bottom pointers of mru list */
+ /* that tracks allocated fxcells */
- int spx_hash_size; /* Current size of simplex hash list */
- simplex **spxhashtop; /* Face simplex hash index list */
+ int spx_hash_size; /* Current size of shared face simplex hash list */
+ simplex **spxhashtop; /* Shared face simplex hash index list */
int nspx; /* Number of simplexes in hash list */
} revcache;
@@ -296,8 +364,8 @@ struct _schbase {
int ixc; /* Cube index of corner that holds maximum input values */
int snsdi, ensdi; /* Start and end extra sub-simplex dimensionality */
- int (*setsort)(struct _schbase *b, cell *c); /* Function to triage & set cube sort index */
- int (*check)(struct _schbase *b, cell *c); /* Function to recheck cube worth keeping */
+ int (*setsort)(struct _schbase *b, fxcell *c); /* Function to triage & set cube sort index */
+ int (*check)(struct _schbase *b, fxcell *c); /* Function to recheck cube worth keeping */
int (*compute)(struct _schbase *b, simplex *x); /* Function to compute a simplex solution */
double v[MXRO+1]; /* Target output value, + ink limit */
@@ -314,7 +382,7 @@ struct _schbase {
double ncdir[MXRO]; /* Normalised clip vector */
double **cla; /* Clip vector LHS implicit equation matrix [fdi][fdi+1] (inc. ink tgt.) */
double clb[MXRO+1]; /* Clip vector RHS implicit equation vector [fdi+1] (inc. ink tgt.) */
- double cdist; /* Best clip locus distance found (aim is min +ve) */
+ double cdist; /* Best clip locus distance found (aim is min +ve) :- weighted for nn */
int iclip; /* NZ if result is above (disabled) ink limit */
int mxsoln; /* Maximum number of solutions that we want */
@@ -328,20 +396,17 @@ struct _schbase {
int axislz; /* Space allocated to axisl[] */
axisec *axisl; /* Auxiliary intersections */
- int lclistz; /* Allocated space to cell sort list */
- cell **lclist; /* Sorted list of pointers to candidate cells */
+ int lclistz; /* Allocated space to fxcell sort list */
+ fxcell **lclist; /* Sorted list of pointers to candidate fxcells */
- int pauxcell; /* Indexe of previous call solution cell, -1 if not relevant */
- int plmaxcell; /* Indexe of previous call solution cell, -1 if not relevant */
- int plmincell; /* Indexe of previous call solution cell, -1 if not relevant */
+ int pauxcell; /* Indexe of previous call solution fxcell, -1 if not relevant */
+ int plmaxcell; /* Indexe of previous call solution fxcell, -1 if not relevant */
+ int plmincell; /* Indexe of previous call solution fxcell, -1 if not relevant */
int lsxfilt; /* Allocated space of simplex filter list */
- char *sxfilt; /* Flag for simplexes that should be in a cell */
+ char *sxfilt; /* Flag for simplexes that should be in an fxcell */
- double crad; /* nn current radius distance */
- double bw; /* nn current window distance */
- int wex[MXRO * 2]; /* nn current window edge indexes */
- double wed[MXRO * 2]; /* nn current window edge distances */
+ int rix; /* Diagnostic - rev[] or nnrev[] index for this point */
}; typedef struct _schbase schbase;
@@ -376,7 +441,12 @@ struct _rev_struct {
/* All other sections depend on this. */
int fastsetup; /* Flag - NZ if fast setup at cost of slow throughput */
- struct _rev_struct *next; /* Linked list of instances sharing memory */
+ int lchweighted; /* Non-zero if nearest search is LCh weighted */
+ double lchw[MXRO]; /* LCh nearest weighting */
+ double lchw_sq[MXRO]; /* LCh nearest weighting squared */
+ double lchw_chsq; /* lchw_sq[1] - lchw_sq[2] */
+
+ struct _rev_struct *next; /* Linked list of global instances sharing memory */
size_t max_sz; /* Maximum size permitted */
size_t sz; /* Total memory current allocated by rev */
@@ -385,32 +455,38 @@ struct _rev_struct {
#endif
/* Reverse grid lookup information */
- int ares; /* Reverse grid allocated resolution, = res + 1, */
- /* allows for extra row used during construction */
int res; /* Reverse grid resolution == ncells on a side */
int no; /* Total number of points in reverse grid = rev.ares ^ fdi */
int coi[MXRO]; /* Coordinate increments for each dimension */
int hoi[1 << MXRO]; /* Coordinate increments for progress through cube */
- datao gl,gh,gw; /* Reverse grid low, high, grid cell width */
+ datao gl,gh,gw; /* Reverse grid low, high, grid bwd cell width */
/* Second section, accelleration information that changes with ink limit. */
int rev_valid; /* nz if this information in rev[] and nnrev[] is valid */
int **rev; /* Exact reverse lookup starting list. */
- /* rev.no pointers to lists of fwd grid indexes. */
- /* First int is allocation length */
- /* Second int is reference count */
- /* Then follows cube indexes */
- /* Last int is -1 */
int **nnrev; /* Nearest reverse lookup starting list. */
- /* rev.no pointers to lists of fwd grid indexes. */
+ /* These lists are of fwd grid indexes. */
/* [0] is allocation length */
- /* [1] is the next free entry index */
- /* [2] is reference count */
+ /* [1] is the next free entry index (length + 3, not counting -1) */
+ /* [2] is index into share lists, -1 if not shared. */
/* Then follows cube indexes */
- /* The last entry is marked with -1 */
+ /* Last entry is marked with -1 */
+
+ double ocent[MXRO]; /* rev cell gamut "center" point for thinning and shadow testing. */
+
+ bxcell *surflist; /* Linked list of rev[] bwd cells that contain gamut surface fwd cells. */
+ /* Used to speed up fill_nncell() when rev.fastsetup is set, else NULL */
+ int surf_hash_size; /* Current size of bxcell hash list */
+ bxcell **surfhash; /* bxcell hash index list */
+
+ int **sharelist; /* Array of pointers to shared (fwd grid list sharer) records. */
+ /* Each record is same format as rev[]/nnrev[], except */
+ /* [2] is used to detect scanning the same list. */
+ int sharellen; /* Size of sharelist */
+ int sharelaloc; /* Allocation size of sharelist */
/* Third section */
- revcache *cache; /* Where cells are allocated and cached */
+ revcache *cache; /* Where fxcells and simplexes are allocated and cached */
/* Sub-dimension simplex information */
ssxinfo sspxi[MXRI+1];/* One per sub dimenstionality at offset sdi */
@@ -425,6 +501,14 @@ struct _rev_struct {
int primsecwarn; /* Not primary or secondary warning has been issued */
+#ifdef CHECK_NNLU
+int cknn_no; /* Number checked */
+double cknn_we; /* Worst DE */
+int cknn_noerrs; /* Number not as good as closet vertex */
+int cknn_nobsb; /* Number not as good as second closest vertex */
+int cknn_nonis; /* Number not in surface */
+#endif /* CHECK_NNLU */
+
}; typedef struct _rev_struct rev_struct;
diff --git a/rspl/revbench.c b/rspl/revbench.c
index 81e668e..f61ff2e 100644
--- a/rspl/revbench.c
+++ b/rspl/revbench.c
@@ -27,6 +27,7 @@
#undef DOLIMIT /* Define to have ink limit */
#define LIMITVAL 2.5 /* Total ink limit sum */
#undef DOCHECK
+#define TESTNN /* Test Nearest Clipping */
#define SHOW_OUTPUT /* Define for printf on each conversion */
@@ -217,6 +218,9 @@ main(int argc, char *argv[]) {
stime = clock();
+#ifdef TESTNN
+ flags |= RSPL_NEARCLIP;
+#endif
/* Itterate though the grid */
for (ops = 0;; ops++) {
int r;
diff --git a/rspl/rspl.c b/rspl/rspl.c
index 431a7e3..db63a47 100644
--- a/rspl/rspl.c
+++ b/rspl/rspl.c
@@ -60,6 +60,7 @@ static void get_out_range(rspl *s, double *min, double *max);
static void get_out_range_points(rspl *s, int *minp, int *maxp);
static double get_out_scale(rspl *s);
static unsigned int get_next_touch(rspl *s);
+static int *get_res(rspl *s);
static int within_restrictedsize(rspl *s);
static int interp_rspl_sx(rspl *s, co *pp);
static int part_interp_rspl_sx(rspl *s, co *p1, co *p2);
@@ -180,6 +181,7 @@ printf("!!!! rspl.c using interp_rspl_nl !!!!");
s->get_out_range = get_out_range;
s->get_out_range_points = get_out_range_points;
s->get_out_scale = get_out_scale;
+ s->get_res = get_res;
s->get_next_touch = get_next_touch;
s->within_restrictedsize = within_restrictedsize;
@@ -416,6 +418,12 @@ rspl *s
}
/* ============================================ */
+/* Return a pointer to the resolution array */
+static int *get_res(rspl *s) {
+ return s->g.res;
+}
+
+/* ============================================ */
/* Return non-zero if this rspl can be */
/* used with Restricted Size functions. */
static int within_restrictedsize(
diff --git a/rspl/rspl.h b/rspl/rspl.h
index ae0a165..7d096f9 100644
--- a/rspl/rspl.h
+++ b/rspl/rspl.h
@@ -19,6 +19,9 @@
/** Configuration **/
+#undef CHECK_NNLU /* [und] Check nn lookup results against exaustive searches */
+ /* as well as other asserts. */
+
/** General Limits **/
#define MXDI 10 /* Maximum input dimensionality */
@@ -43,6 +46,7 @@
#define POW2MXRI 16 /* 2 ^ MXRI */
#define POW3MXRI 81 /* 3 ^ MXRI */
#define HACOMPS ((POW3MXRI + 2 * MXRI + 1)/2) /* Maximum number of array components */
+#define POW2MXRO 1024 /* 2 ^ MXRO */
#if MXRI > MXRO /* Maximum of either RI or RO */
# define MXRIRO MXRI
@@ -175,7 +179,7 @@ struct _rspl {
/* Array is res[] ^ di entries float[fdi+G_XTRA], offset by G_XTRA */
/* (But is expanded when spline interpolaton is active) */
/* float[-1] contains the ink limit function value, L_UNINIT if not initd */
- /* float[-2] contains the edge flag values, 2 bits per in dim. */
+ /* float[-2] contains the edge flag values, 3 bits per in dim. */
/* float[-3] contains the touched flag generation count. */
/* (k value for non-linear fit would be another entry.) */
/* Flag values are 3 bits for each dimension. Bits 1,0 form */
@@ -188,9 +192,15 @@ struct _rspl {
/* Uninitialised limit value */
#define L_UNINIT ((float)-1e38)
+#define FL_BITS 3 /* flag bits per dimension */
/* Macros to access flags. Arguments are a pointer to base grid point and */
/* Flag value is distance from edge in bottom 2 bits, values 0, 1 or 2 maximum. */
- /* bit 2 is set if the distance is to the lower edge. */
+ /* bit 2 is set if the distance is to the lower edge. ie: */
+ /* 0 = at top edge */
+ /* 1 = next to top edge */
+ /* 2, 6 = not at or next to any edge */
+ /* 4 = at bottom edge */
+ /* 5 = next to bottom edge */
#define FLV(fp) (*((unsigned int *)((fp)-2)))
/* Init the flag values to 0 */
#define I_FL(fp) (FLV(fp) = 0)
@@ -407,8 +417,8 @@ struct _rspl {
void
(*scan_rspl)(
struct _rspl *s, /* this */
- int flags, /* Combination of flags (not used) */
- void *cbntx, /* Opaque function context */
+ int flags, /* Combination of flags (not used) */
+ void *cbntx, /* Opaque function context */
void (*func)(void *cbntx, double *out, double *in) /* Function that gets given values */
);
@@ -442,8 +452,8 @@ struct _rspl {
void
(*filter_rspl)(
struct _rspl *s, /* this */
- int flags, /* Combination of flags (not used) */
- void *cbntx, /* Opaque function context */
+ int flags, /* Combination of flags (not used) */
+ void *cbntx, /* Opaque function context */
void (*func)(void *cbntx, float **out, double *in, int cvi) /* Function to set from */
);
@@ -510,17 +520,26 @@ struct _rspl {
double *limitv /* Return limit value */
);
+ /* Set the RSPL_NEARCLIP LCh weightings. */
+ /* Will only work with L*a*b* like output spaces. */
+ /* Calling this will clear the reverse interpolaton cache. */
+ void (*rev_set_lchw)(
+ struct _rspl *s, /* this */
+ double lchw[MXRO] /* Weighting */
+ );
+
/* Possible reverse hint flags */
-#define RSPL_WILLCLIP 0x0001 /* Hint that clipping will be needed */
-#define RSPL_EXACTAUX 0x0002 /* Hint that auxiliary target will be matched exactly */
-#define RSPL_MAXAUX 0x0004 /* If not possible to match exactly, return the */
+#define RSPL_WILLCLIP 0x0001 /* Hint that clipping will be needed */
+#define RSPL_EXACTAUX 0x0002 /* Hint that auxiliary target will be matched exactly */
+#define RSPL_MAXAUX 0x0004 /* If not possible to match exactly, return the */
/* closest value larger than the target, rather than */
/* absolute closest. */
-#define RSPL_AUXLOCUS 0x0008 /* Auxiliary target is proportion of locus, not */
+#define RSPL_AUXLOCUS 0x0008 /* Auxiliary target is proportion of locus, not */
/* absolute. Implies EXACTAUX hint. */
-#define RSPL_NEARCLIP 0x0010 /* If clipping occurs, return the nearest solution, */
+#define RSPL_NEARCLIP 0x0010 /* If clipping occurs, return the nearest solution, */
/* rather than the one in the clip direction. */
-
+#define RSPL_NONNSETUP 0x0020 /* Sets RSPL_FASTREVSETUP flag, which avoids NN grid */
+ /* setup if this is the first call using RSPL_NEARCLIP. */
/* Return value masks */
#define RSPL_DIDCLIP 0x8000 /* If this bit is set, at least one soln. and clipping occured */
#define RSPL_NOSOLNS 0x7fff /* And return value with this mask to get number of solutions */
@@ -587,6 +606,9 @@ struct _rspl {
# define wvals ad##jw
+ /* Return a pointer to the resolution array */
+ int *(*get_res)(struct _rspl *s);
+
/* Return non-zero if this rspl can be */
/* used with Restricted Size functions. */
int (*within_restrictedsize)(
diff --git a/rspl/rspl1.c b/rspl/rspl1.c
index dc3588b..3996269 100644
--- a/rspl/rspl1.c
+++ b/rspl/rspl1.c
@@ -1,5 +1,5 @@
- /* Single dimension regularized spline data structure */
+/* Single dimension regularized spline data structure */
/*
* Argyll Color Correction System
@@ -339,6 +339,11 @@ static int fit_rspl(
smooth, avgdev, ipos);
}
+/* Return a pointer to the resolution array */
+static int *get_res(rspl *s) {
+ return &s->nig;
+}
+
/* Initialise the regular spline from scattered data with weights */
/* Return nz on error */
static int
@@ -361,6 +366,80 @@ fit_rspl_w(
smooth, avgdev, ipos);
}
+/* Initialize the grid from a provided function. */
+/* Grid index values are supplied "under" in[] at *((int*)&iv[-e-1]) */
+static int set_rspl(
+ struct _rspl *s,/* this */
+ int flags, /* (Not used) */
+ void *cbctx, /* Opaque function context */
+ void (*func)(void *cbctx, double *out, double *in), /* Function to set from */
+ datai glow, /* Grid low scale, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale, NULL = default 1.0 */
+ int *gres, /* Spline grid resolution for each dimension */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh /* Data value high normalize, NULL = default 1.0 */
+) {
+ int n;
+ double _iv[2 * MXDI], *iv = &_iv[MXDI]; /* Real index value/table value */
+ double ov[MXDO];
+
+ DBGF((DBGA, "rspl1:set_rspl() callen"));
+
+ /* Allocate space for interpolation grid */
+ s->nig = *gres;
+
+ if ((s->x = dvector(0, s->nig)) == NULL) {
+ DBGF((DBGA, "rspl1:Malloc of vector x failed\n"));
+ return 1;
+ }
+
+ s->xl = s->gl = glow != NULL ? *glow : 0.0;
+ s->xh = s->gh = ghigh != NULL ? *ghigh : 1.0;
+
+ /* Set the input scaling */
+ s->gw = (s->gh - s->gl)/(double)(s->nig-1);
+
+ /* Set the default output scaling */
+ s->vl = vlow != NULL ? *vlow : 0.0;
+ s->vw = ((vhigh != NULL ? *vhigh : 1.0) - s->vl);
+
+ DBGF((DBGA, "rspl1:gl %f, gh %f, gw %f, vl %f, vw %f\n",s->gl,s->gh,s->gw,s->vl,s->vw));
+
+ /* Lookup the values at the grid points */
+ for (n = 0; n < s->nig; n++) {
+ double vv;
+
+ /* Compute grid pointer and input sample values */
+ iv[0] = s->gl + n * s->gw; /* Input sample values */
+ *((int *)&iv[-1-1]) = n; /* Trick to supply grid index in iv[] */
+
+ /* Apply incolor -> outcolor function we want to represent */
+ func(cbctx, ov, iv);
+
+ s->x[n] = (float)ov[0]; /* Set unscaled output value */
+
+ if (s->x[n] < s->dl)
+ s->dl = s->x[n];
+ if (s->x[n] > s->dh)
+ s->dh = s->x[n];
+ }
+
+ /* Adjust output scaling */
+ s->vw += s->vl; /* Convert to high */
+ if (s->dl < s->vl)
+ s->vl = s->dl;
+ if (s->dh < s->vw)
+ s->vw = s->dh;
+ s->vw -= s->vl; /* Convert to width */
+
+ /* Apply scaling to data */
+ for (n = 0; n < s->nig; n++) {
+ s->x[n] = (s->x[n] - s->vl)/s->vw;
+ }
+
+ return 0;
+}
+
/* Construct an empty rspl1 */
/* Return NULL if something goes wrong. */
rspl *new_rspl(int flags, int di, int fdi) {
@@ -380,6 +459,8 @@ rspl *new_rspl(int flags, int di, int fdi) {
t->interp = interp;
t->fit_rspl = fit_rspl;
t->fit_rspl_w = fit_rspl_w;
+ t->set_rspl = set_rspl;
+ t->get_res = get_res;
t->del = del_rspl;
return t;
diff --git a/rspl/rspl1.h b/rspl/rspl1.h
index 747abd5..63be428 100644
--- a/rspl/rspl1.h
+++ b/rspl/rspl1.h
@@ -1,7 +1,7 @@
#ifndef _RSPL1_H_
- /* Single dimension regularized spline data structure */
+/* Single dimension regularized spline data structure */
/*
* Argyll Color Correction System
@@ -18,10 +18,22 @@
*
*/
+/*
+ * Might be nice to add support for simple rev lookup, so that
+ * standalone xcal can use it ??
+ */
+
+
#ifdef __cplusplus
extern "C" {
#endif
+/* Make up for possible lack of rspl.h */
+#ifndef MXDI
+# define MXDI 10 /* Maximum input dimensionality */
+# define MXDO 10 /* Maximum output dimensionality (Is not fully tested!!!) */
+#endif
+
/* General data point position/value structure */
typedef double datai[1];
typedef double datao[1];
@@ -94,12 +106,30 @@ struct _rspl {
double **ipos /* (not used) */
);
+ /* Initialize the grid from a provided function. */
+ /* Grid index values are supplied "under" in[] at *((int*)&in[-e-1]) */
+ int
+ (*set_rspl)(
+ struct _rspl *s, /* this */
+ int flags, /* (Not used) */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, double *out, double *in), /* Function to set from */
+ datai glow, /* Grid low scale, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh /* Data value high normalize - NULL = default 1.0 */
+ );
+
/* Do forward interpolation */
/* Return 0 if OK, 1 if input was clipped to grid */
int (*interp)(
struct _rspl *s, /* this */
co *p); /* Input and output values */
+ /* Return a pointer to the resolution array */
+ int *(*get_res)(struct _rspl *s);
+
}; typedef struct _rspl rspl;
/* Create a new, empty rspl object */
diff --git a/rspl/scat.c b/rspl/scat.c
index f1535fa..f94e074 100644
--- a/rspl/scat.c
+++ b/rspl/scat.c
@@ -72,7 +72,7 @@
a curvature error).
The default assumption is that the grid resolution is set
- to matche the input data range for that dimension, eg. if
+ to match the input data range for that dimension, eg. if
a sub range of input space is all that is needed, then a
smaller grid resolution can/should be used if smoothness
is expected to remain symetric in relation to the input
@@ -129,13 +129,17 @@
/* algorithm parameters [Release defaults] */
#define INCURVEADJ /* [Defined] Adjust smoothness criteria for input curve grid spacing */
-#undef SMOOTH2 /* [Undef] INCOMPLETE Use 3nd order smoothness rather than curvature. */
+#undef SMOOTH2 /* [Undef] INCOMPLETE - would be nice to finish this to help XYZ! */
+ /* Use 3nd order smoothness rather than curvature. */
/* 2nd order is optimal about 2.5 x lower than 3rd order, */
/* so an even split between 3rd:2nd would be 1.0 0.4, */
/* a 9:1 split would be 0.9 0.04 */
/* This also disables the incorrect scaling of smoothness with */
/* output range */
#undef AUTOSM /* [Undef] INCOMPLETE Support auto smoothing using LOOCV */
+ /* - started implementing this using shadow grid map of */
+ /* smoothness (see see mgtmp *sm), then switch to */
+ /* Leave One Out Cross Validation (LOOCV) idea. */
# define CW2 0.9
# define CW ((1.0 - CW2) * 0.4)
@@ -275,6 +279,7 @@ struct _loocv {
/* in the list in the cell. -1 for no more data */
double *sm; /* smoothness map grid data values in log space, 0.0 for none */
+ /* (Not fully implemented, and being superceeded) */
double **As; /* A matrix of smoothness vertex weights */
double *bs; /* b vector for RHS of smoothness equation */
@@ -1725,7 +1730,7 @@ print_smsens(mgtmp *m) {
of any sum term that does not have the grid point in question in it
will have a partial derivative of zero, each row equation consists
of just those terms that have that grid points value in it,
- with the vast majoroty of the sum terms omitted.
+ with the vast majority of the sum terms omitted.
*/
@@ -1871,7 +1876,7 @@ mgtmp *sm /* Optional smoothing map for ausm mode */
/* The ipos[] factor is to allow for the possibility that the */
/* grid spacing may be non-uniform in the colorspace where the */
/* function being modelled is smooth. Our curvature computation */
- /* needs to make allowsance for this fact in computing the */
+ /* needs to make allowance for this fact in computing the */
/* node value differences that equate to zero curvature. */
/*
The old curvature fixed grid spacing equation was:
@@ -2078,7 +2083,7 @@ mgtmp *sm /* Optional smoothing map for ausm mode */
}
/* We setup the equation to be solved for each grid point. */
- /* Each grid point participates in foure curvature equations, */
+ /* Each grid point participates in four curvature equations, */
/* one centered on the grid line below, one that it's the center of, */
/* one centered on the grid line above, and one centered on the */
/* grid line two above. The equation setup is for the differential */
diff --git a/rspl/tnd.c b/rspl/tnd.c
index c6f0911..89718d9 100644
--- a/rspl/tnd.c
+++ b/rspl/tnd.c
@@ -22,7 +22,7 @@
#include "rspl.h"
#include "numlib.h"
#include "tiffio.h"
-#include "plot.h"
+//#include "plot.h"
#ifdef NEVER
FILE *verbose_out = stdout;
@@ -217,7 +217,7 @@ int main(int argc, char *argv[]) {
cvec[3] = 0.0 - tp[0].v[3];
/* Do reverse interpolation ~~~1 */
- if ((r = rss->rev_interp(rss, 0, NIP, auxm, NULL /*cvec*/, tp)) > 0) {
+ if ((r = rss->rev_interp(rss, 0, NIP, auxm, NULL /*cvec/LChW*/, tp)) > 0) {
printf("Total of %d Results\n",r);
for (i = 0; i < r; i++)
printf("Result %d = %f, %f, %f, %f\n",i, tp[i].p[0],tp[i].p[1],tp[i].p[2],tp[i].p[3]);
diff --git a/scanin/CMP_Digital_Target-4.ti2 b/scanin/CMP_Digital_Target-4.ti2
index e4b15e9..8cc38ea 100644
--- a/scanin/CMP_Digital_Target-4.ti2
+++ b/scanin/CMP_Digital_Target-4.ti2
@@ -1,6 +1,6 @@
CTI2
-DESCRIPTOR "Argyll Calibration Target chart information 2 for Christopher Metarie Digital Target 3"
+DESCRIPTOR "Argyll Calibration Target chart information 2 for Christopher Metarie Digital Target 4"
ORIGINATOR "Argyll printtarg"
CREATED "Wed Sep 12 00:02:26 2007"
KEYWORD "TARGET_INSTRUMENT"
diff --git a/scanin/CMP_Digital_Target-7.cht b/scanin/CMP_Digital_Target-7.cht
new file mode 100644
index 0000000..d188517
--- /dev/null
+++ b/scanin/CMP_Digital_Target-7.cht
@@ -0,0 +1,638 @@
+
+BOXES 571
+ F _ _ 100 200 3100 200 3100 2100 100 2100
+ D ALL ALL _ _ 3200 2100 0 100 0 0
+ X A Z 1 19 100 100 100 200 100 100
+ X 2A 2D 1 19 100 100 2700 200 100 100
+
+BOX_SHRINK 12
+
+REF_ROTATION 0.0
+
+XLIST 31
+ 100 1 1
+ 200 1 1
+ 300 1 1
+ 400 1 1
+ 500 1 1
+ 600 1 1
+ 700 1 1
+ 800 1 1
+ 900 1 1
+ 1000 1 1
+ 1100 1 1
+ 1200 1 1
+ 1300 1 1
+ 1400 1 1
+ 1500 1 1
+ 1600 1 1
+ 1700 1 1
+ 1800 1 1
+ 1900 1 1
+ 2000 1 1
+ 2100 1 1
+ 2200 1 1
+ 2300 1 1
+ 2400 1 1
+ 2500 1 1
+ 2600 1 1
+ 2700 1 1
+ 2800 1 1
+ 2900 1 1
+ 3000 1 1
+ 3100 1 1
+
+YLIST 21
+ 200 1 1
+ 300 1 1
+ 400 1 1
+ 500 1 1
+ 600 1 1
+ 700 1 1
+ 800 1 1
+ 900 1 1
+ 1000 1 1
+ 1100 1 1
+ 1200 1 1
+ 1300 1 1
+ 1400 1 1
+ 1500 1 1
+ 1500 1 1
+ 1600 1 1
+ 1700 1 1
+ 1800 1 1
+ 1900 1 1
+ 2000 1 1
+ 2100 1 1
+
+EXPECTED XYZ 570
+ A1 31.9 22.6 21.2
+ A2 7.6 21.5 7.5
+ A3 72.2 69.4 57.8
+ A4 20.9 34.4 14.4
+ A5 79.8 83.0 57.4
+ A6 37.7 36.5 30.8
+ A7 13.6 14.4 45.1
+ A8 65.7 60.9 23.2
+ A9 24.7 16.2 33.1
+ A10 2.5 1.4 7.6
+ A11 31.1 15.9 1.3
+ A12 29.7 32.5 50.3
+ A13 10.4 15.3 28.4
+ A14 18.4 28.1 7.1
+ A15 12.1 19.0 18.5
+ A16 29.9 47.3 21.8
+ A17 19.8 14.3 30.7
+ A18 41.8 24.4 1.5
+ A19 12.1 11.0 36.1
+ B1 20.9 13.2 29.7
+ B2 8.7 8.5 34.4
+ B3 2.3 1.5 2.4
+ B4 20.0 15.3 37.2
+ B5 15.5 8.4 1.2
+ B6 40.6 22.0 28.0
+ B7 16.3 33.2 10.0
+ B8 9.0 23.6 7.5
+ B9 46.9 62.0 25.3
+ B10 5.0 12.8 6.1
+ B11 16.1 8.4 16.3
+ B12 41.6 57.7 10.6
+ B13 13.9 9.9 28.1
+ B14 30.7 18.0 29.8
+ B15 27.9 13.9 17.4
+ B16 34.8 18.3 1.3
+ B17 16.0 32.5 17.9
+ B18 77.1 81.7 62.3
+ B19 42.7 29.8 12.1
+ C1 17.0 34.3 13.1
+ C2 25.7 13.2 1.4
+ C3 32.5 50.1 22.9
+ C4 16.0 18.7 1.6
+ C5 32.6 32.1 54.2
+ C6 13.4 16.4 47.5
+ C7 12.8 10.1 31.5
+ C8 41.0 37.8 1.7
+ C9 40.0 29.0 36.6
+ C10 26.8 31.3 1.9
+ C11 3.5 9.5 2.3
+ C12 9.1 7.9 31.1
+ C13 18.4 28.5 2.7
+ C14 7.2 7.6 35.4
+ C15 18.9 33.4 39.7
+ C16 44.9 39.1 13.4
+ C17 2.4 1.7 9.2
+ C18 45.9 31.4 42.3
+ C19 2.0 4.2 1.5
+ D1 3.5 2.7 17.7
+ D2 19.4 21.4 42.5
+ D3 8.2 7.4 31.0
+ D4 21.7 26.2 55.4
+ D5 20.5 38.0 7.7
+ D6 48.0 31.0 5.2
+ D7 80.7 83.9 61.0
+ D8 22.4 15.0 20.4
+ D9 4.8 13.5 2.8
+ D10 9.4 23.6 13.7
+ D11 71.6 66.5 59.1
+ D12 21.1 38.6 10.1
+ D13 35.8 17.9 12.3
+ D14 57.6 67.8 59.6
+ D15 26.8 44.2 5.8
+ D16 2.0 4.9 5.4
+ D17 40.2 34.7 13.7
+ D18 6.6 9.0 4.1
+ D19 51.9 44.0 27.1
+ E1 32.3 34.5 15.5
+ E2 29.9 17.4 29.0
+ E3 39.5 42.9 15.5
+ E4 55.3 42.2 6.4
+ E5 23.8 24.5 22.9
+ E6 9.0 18.1 6.4
+ E7 10.5 8.8 31.7
+ E8 9.8 25.0 7.6
+ E9 74.1 71.0 48.7
+ E10 48.2 59.8 60.9
+ E11 47.6 31.4 1.9
+ E12 8.4 7.7 7.1
+ E13 7.4 7.4 33.5
+ E14 24.6 12.3 5.5
+ E15 27.4 26.1 22.7
+ E16 41.6 28.8 4.8
+ E17 1.2 2.8 3.2
+ E18 77.3 76.1 57.2
+ E19 45.5 60.1 4.3
+ F1 42.3 22.5 26.0
+ F2 43.9 39.2 7.1
+ F3 7.8 7.4 32.0
+ F4 12.3 15.9 46.9
+ F5 31.2 16.0 1.3
+ F6 37.9 21.6 31.1
+ F7 9.1 23.4 4.2
+ F8 19.0 12.1 28.6
+ F9 8.1 8.5 36.2
+ F10 34.7 21.2 34.1
+ F11 33.2 37.5 26.6
+ F12 72.6 80.1 26.5
+ F13 54.3 57.6 28.9
+ F14 17.5 18.8 6.2
+ F15 41.9 23.1 17.6
+ F16 37.4 36.2 54.6
+ F17 45.2 45.8 21.8
+ F18 9.2 8.0 31.4
+ F19 24.0 21.5 12.7
+ G1 15.0 17.1 13.6
+ G2 16.8 17.7 47.7
+ G3 50.7 64.8 40.5
+ G4 66.0 71.2 28.6
+ G5 19.9 36.8 25.4
+ G6 15.6 32.5 18.2
+ G7 15.3 13.4 38.6
+ G8 14.5 31.2 12.6
+ G9 57.8 44.3 21.9
+ G10 14.3 25.5 42.1
+ G11 6.4 3.7 6.6
+ G12 33.6 34.6 31.0
+ G13 4.1 6.2 16.1
+ G14 26.7 14.0 1.3
+ G15 34.9 47.5 27.1
+ G16 40.7 29.1 1.3
+ G17 37.4 20.1 1.5
+ G18 8.0 21.2 3.8
+ G19 28.9 41.3 13.5
+ H1 43.0 25.0 9.0
+ H2 38.5 21.6 1.4
+ H3 8.5 7.5 31.0
+ H4 42.0 23.7 30.9
+ H5 17.8 28.2 2.8
+ H6 1.4 1.1 4.8
+ H7 51.7 64.1 4.1
+ H8 1.8 1.5 1.8
+ H9 4.7 9.1 8.9
+ H10 22.5 42.9 28.6
+ H11 60.6 59.2 43.6
+ H12 2.6 1.7 12.1
+ H13 74.8 77.5 52.1
+ H14 23.8 40.8 23.3
+ H15 38.7 24.4 36.0
+ H16 18.1 12.8 31.6
+ H17 24.9 21.0 45.0
+ H18 30.5 18.8 30.8
+ H19 14.6 25.6 24.7
+ I1 5.7 4.0 19.0
+ I2 12.8 9.4 28.2
+ I3 29.3 44.1 3.0
+ I4 8.1 7.5 32.0
+ I5 1.4 2.0 1.2
+ I6 49.0 42.5 28.4
+ I7 7.1 7.3 34.5
+ I8 17.5 34.0 23.3
+ I9 35.8 22.1 34.9
+ I10 10.0 24.9 11.3
+ I11 6.7 7.3 1.2
+ I12 16.1 32.9 21.4
+ I13 8.6 8.9 32.0
+ I14 21.2 13.5 29.3
+ I15 7.9 8.7 34.2
+ I16 78.9 81.9 68.4
+ I17 44.3 60.2 17.1
+ I18 13.9 30.5 12.5
+ I19 13.0 7.2 1.4
+ J1 9.7 23.5 6.5
+ J2 12.4 28.5 7.7
+ J3 17.8 24.2 56.1
+ J4 76.2 80.6 47.7
+ J5 20.6 35.9 34.0
+ J6 1.9 1.4 7.7
+ J7 72.5 70.7 46.5
+ J8 0.9 0.8 2.0
+ J9 54.8 44.5 1.8
+ J10 57.7 42.8 13.1
+ J11 57.7 59.9 46.7
+ J12 14.2 6.8 15.7
+ J13 24.0 21.2 1.6
+ J14 8.1 15.3 12.5
+ J15 68.4 59.9 38.8
+ J16 17.9 15.1 6.1
+ J17 5.0 4.5 2.1
+ J18 53.3 37.1 26.2
+ J19 26.2 37.2 33.5
+ K1 17.1 11.8 29.9
+ K2 1.8 1.8 1.1
+ K3 40.6 22.8 9.9
+ K4 8.8 14.3 27.9
+ K5 35.3 20.8 31.6
+ K6 20.0 33.3 47.9
+ K7 12.2 21.3 7.6
+ K8 6.7 5.4 20.8
+ K9 12.8 18.9 30.3
+ K10 31.1 19.6 22.4
+ K11 56.6 55.4 6.7
+ K12 21.6 12.2 1.9
+ K13 25.4 38.1 57.2
+ K14 24.3 21.7 46.4
+ K15 7.9 7.4 5.5
+ K16 49.2 55.7 9.0
+ K17 33.0 49.9 31.4
+ K18 81.4 84.5 65.4
+ K19 25.8 16.6 5.3
+ L1 66.6 68.8 62.7
+ L2 37.1 36.0 26.7
+ L3 36.6 40.4 56.0
+ L4 36.6 22.5 34.7
+ L5 20.2 35.7 32.8
+ L6 31.2 30.0 13.0
+ L7 21.6 12.2 2.0
+ L8 0.8 0.8 0.7
+ L9 0.7 0.7 0.6
+ L10 0.9 0.9 0.8
+ L11 1.2 1.2 1.1
+ L12 12.2 21.2 7.5
+ L13 3.6 2.3 14.9
+ L14 26.0 12.6 6.3
+ L15 51.3 56.3 17.2
+ L16 59.3 65.3 54.1
+ L17 37.2 20.2 2.3
+ L18 14.7 11.3 5.9
+ L19 20.3 35.8 34.4
+ M1 2.5 1.9 1.2
+ M2 40.3 22.5 29.7
+ M3 21.1 42.5 14.2
+ M4 11.8 16.5 15.5
+ M5 10.3 5.9 1.2
+ M6 12.6 25.3 14.4
+ M7 56.7 55.4 6.8
+ M8 1.5 1.5 1.3
+ M9 1.5 1.6 1.3
+ M10 1.8 1.9 1.5
+ M11 1.9 1.9 1.6
+ M12 6.7 5.3 20.7
+ M13 23.4 43.2 12.5
+ M14 53.4 45.9 47.1
+ M15 22.4 20.7 37.0
+ M16 8.6 7.8 31.8
+ M17 4.6 3.1 1.3
+ M18 62.8 60.2 2.6
+ M19 3.7 2.7 1.3
+ N1 28.2 32.6 47.8
+ N2 17.8 16.7 14.7
+ N3 35.0 38.6 31.1
+ N4 28.7 14.8 1.3
+ N5 15.1 30.2 29.6
+ N6 59.7 49.0 31.7
+ N7 31.0 19.6 22.4
+ N8 2.3 2.3 1.9
+ N9 2.5 2.6 2.1
+ N10 2.7 2.8 2.3
+ N11 2.9 2.9 2.4
+ N12 13.1 18.9 30.3
+ N13 14.4 14.5 45.8
+ N14 48.3 36.3 1.0
+ N15 5.8 5.5 3.6
+ N16 17.8 32.2 19.1
+ N17 19.1 33.8 35.3
+ N18 34.8 21.1 33.0
+ N19 7.6 20.5 3.8
+ O1 29.2 45.4 39.0
+ O2 41.2 23.7 12.0
+ O3 30.4 15.5 1.3
+ O4 14.4 29.3 28.1
+ O5 1.3 1.2 1.0
+ O6 42.4 36.8 52.8
+ O7 12.9 19.0 30.5
+ O8 4.0 4.1 3.3
+ O9 5.8 6.0 4.7
+ O10 7.6 7.9 6.2
+ O11 8.5 8.8 7.0
+ O12 31.0 19.6 22.4
+ O13 40.7 33.1 14.4
+ O14 9.8 13.1 5.2
+ O15 34.6 22.4 3.0
+ O16 23.3 28.6 35.2
+ O17 34.8 17.2 12.5
+ O18 22.8 26.2 17.9
+ O19 25.2 12.8 1.5
+ P1 64.4 66.6 43.5
+ P2 20.5 28.7 46.5
+ P3 12.4 9.4 28.8
+ P4 4.5 2.6 4.6
+ P5 45.0 51.5 35.8
+ P6 60.3 69.7 4.5
+ P7 6.8 5.4 20.9
+ P8 11.9 12.3 9.9
+ P9 13.8 14.3 11.5
+ P10 15.8 16.4 13.1
+ P11 18.6 19.3 15.5
+ P12 58.6 57.7 7.1
+ P13 7.4 15.4 33.0
+ P14 23.8 23.1 33.3
+ P15 6.6 13.1 2.1
+ P16 29.5 19.6 4.5
+ P17 20.7 20.1 27.9
+ P18 47.5 30.7 9.3
+ P19 9.9 23.4 23.2
+ Q1 28.1 14.4 1.3
+ Q2 9.3 5.4 1.4
+ Q3 23.8 27.7 6.1
+ Q4 19.6 28.6 14.4
+ Q5 12.9 11.7 1.3
+ Q6 7.6 7.5 33.6
+ Q7 12.2 21.3 7.6
+ Q8 21.3 22.2 17.8
+ Q9 25.1 26.2 20.9
+ Q10 30.9 32.2 26.0
+ Q11 35.4 36.8 29.7
+ Q12 20.8 11.7 1.8
+ Q13 6.6 8.4 5.6
+ Q14 15.9 14.9 16.8
+ Q15 9.9 9.0 39.5
+ Q16 20.1 20.2 28.5
+ Q17 34.9 18.3 1.4
+ Q18 10.8 8.8 30.7
+ Q19 51.3 43.9 42.6
+ R1 1.0 1.7 1.7
+ R2 21.7 37.2 35.0
+ R3 33.0 26.0 44.3
+ R4 35.3 21.7 34.5
+ R5 63.9 61.6 52.8
+ R6 72.6 70.6 54.1
+ R7 21.6 12.2 2.0
+ R8 39.9 41.5 33.6
+ R9 45.7 47.4 38.6
+ R10 50.8 52.7 42.6
+ R11 57.2 59.4 48.2
+ R12 11.6 20.6 7.4
+ R13 15.2 26.0 26.9
+ R14 39.4 33.9 16.0
+ R15 28.3 29.3 19.2
+ R16 39.3 30.3 15.8
+ R17 60.8 49.5 52.7
+ R18 21.3 38.8 13.5
+ R19 31.4 16.1 1.2
+ S1 13.7 30.4 12.7
+ S2 39.9 21.6 27.3
+ S3 9.0 16.6 2.2
+ S4 19.2 20.0 15.7
+ S5 3.7 6.9 1.6
+ S6 44.5 25.3 29.8
+ S7 56.7 55.5 6.8
+ S8 64.0 66.5 54.2
+ S9 71.8 74.4 60.6
+ S10 80.2 83.3 67.4
+ S11 82.9 86.1 70.1
+ S12 6.6 5.2 19.6
+ S13 31.1 35.8 2.9
+ S14 29.2 18.4 8.8
+ S15 5.6 15.6 3.2
+ S16 18.4 13.3 7.0
+ S17 9.2 23.5 4.2
+ S18 54.2 43.2 2.0
+ S19 8.5 7.7 31.3
+ T1 27.1 17.2 31.4
+ T2 11.1 10.9 37.5
+ T3 32.1 16.5 1.1
+ T4 10.7 25.2 3.7
+ T5 47.7 52.9 42.7
+ T6 8.8 14.6 6.0
+ T7 31.3 19.8 22.6
+ T8 13.0 19.0 30.5
+ T9 6.8 5.4 20.8
+ T10 12.3 21.3 7.6
+ T11 21.6 12.2 2.0
+ T12 56.4 55.2 6.7
+ T13 18.3 11.9 28.5
+ T14 19.6 36.8 5.4
+ T15 38.2 21.2 1.4
+ T16 6.0 7.7 16.7
+ T17 1.7 1.4 1.1
+ T18 4.1 12.1 6.4
+ T19 12.0 28.0 6.6
+ U1 64.4 73.6 9.8
+ U2 8.7 22.6 3.9
+ U3 13.6 14.3 44.6
+ U4 13.1 29.1 19.5
+ U5 6.5 13.1 2.0
+ U6 45.7 31.7 25.9
+ U7 34.9 46.2 64.6
+ U8 11.4 26.6 4.0
+ U9 1.7 2.1 1.8
+ U10 56.0 42.9 49.4
+ U11 58.0 46.5 26.1
+ U12 33.9 17.4 1.4
+ U13 22.4 24.9 6.2
+ U14 27.5 13.9 16.1
+ U15 15.9 32.5 20.2
+ U16 33.3 17.3 1.1
+ U17 26.5 28.1 53.0
+ U18 79.1 80.2 65.2
+ U19 44.1 41.1 4.6
+ V1 5.9 13.4 14.4
+ V2 40.0 50.4 42.4
+ V3 15.1 31.8 6.4
+ V4 10.8 5.8 10.8
+ V5 59.9 52.9 31.4
+ V6 6.7 7.9 5.1
+ V7 30.6 17.9 29.5
+ V8 16.8 23.4 56.2
+ V9 35.0 26.2 13.8
+ V10 8.0 22.0 7.1
+ V11 5.4 3.4 1.1
+ V12 28.2 46.1 14.8
+ V13 14.0 7.1 5.9
+ V14 20.2 19.2 11.1
+ V15 30.1 18.6 32.1
+ V16 16.4 32.8 22.8
+ V17 57.3 43.5 12.4
+ V18 49.7 32.6 21.1
+ V19 48.7 53.0 61.0
+ W1 72.6 79.0 34.3
+ W2 8.7 6.2 2.6
+ W3 19.0 17.6 45.1
+ W4 10.3 11.7 1.5
+ W5 28.3 29.3 19.2
+ W6 45.8 26.8 33.1
+ W7 6.9 13.6 14.0
+ W8 39.7 59.2 22.8
+ W9 27.9 45.6 10.2
+ W10 0.9 1.3 1.5
+ W11 18.6 32.0 44.2
+ W12 40.9 23.6 4.4
+ W13 64.3 56.8 32.7
+ W14 67.4 72.9 4.1
+ W15 2.8 6.8 1.9
+ W16 29.9 17.3 28.7
+ W17 72.9 75.2 65.6
+ W18 4.1 9.1 9.5
+ W19 1.7 5.0 2.0
+ X1 15.8 26.4 44.2
+ X2 42.9 55.2 46.0
+ X3 22.3 11.7 1.1
+ X4 82.6 85.8 69.6
+ X5 1.4 1.2 1.0
+ X6 32.6 46.8 15.6
+ X7 31.0 34.4 7.5
+ X8 80.2 81.7 65.2
+ X9 66.8 58.4 56.3
+ X10 11.2 26.7 11.9
+ X11 29.4 29.9 54.4
+ X12 14.9 15.3 15.1
+ X13 14.6 8.4 1.0
+ X14 12.6 9.6 1.4
+ X15 56.7 63.5 44.2
+ X16 36.0 19.1 1.3
+ X17 44.9 52.8 2.8
+ X18 69.3 76.2 62.8
+ X19 63.9 73.0 7.6
+ Y1 38.6 52.7 30.2
+ Y2 16.0 19.6 8.5
+ Y3 57.3 43.4 33.4
+ Y4 26.5 22.1 5.5
+ Y5 5.7 15.8 3.3
+ Y6 58.4 46.3 51.3
+ Y7 81.7 84.3 66.0
+ Y8 14.3 11.1 1.3
+ Y9 4.4 13.9 3.1
+ Y10 64.1 60.7 8.8
+ Y11 18.0 34.1 27.2
+ Y12 34.9 18.4 1.3
+ Y13 23.5 39.2 35.9
+ Y14 45.7 47.1 44.0
+ Y15 27.1 18.6 36.9
+ Y16 12.4 28.5 7.3
+ Y17 39.4 40.7 27.4
+ Y18 3.5 9.1 2.2
+ Y19 15.1 13.9 7.7
+ Z1 28.1 23.3 15.1
+ Z2 63.2 58.8 7.8
+ Z3 4.1 11.1 2.4
+ Z4 1.1 0.9 2.9
+ Z5 73.3 79.9 64.5
+ Z6 8.6 9.0 5.5
+ Z7 7.9 7.8 33.6
+ Z8 28.8 44.3 38.3
+ Z9 31.3 16.0 1.1
+ Z10 27.4 26.5 19.1
+ Z11 2.0 1.4 8.3
+ Z12 8.5 7.7 31.5
+ Z13 15.6 18.1 1.7
+ Z14 18.3 34.1 3.7
+ Z15 2.0 2.1 0.9
+ Z16 33.5 24.8 41.9
+ Z17 6.7 3.4 6.7
+ Z18 63.8 57.5 14.1
+ Z19 78.3 82.8 66.9
+ 2A1 0.9 1.1 0.9
+ 2A2 19.6 13.8 5.9
+ 2A3 38.7 21.2 9.9
+ 2A4 12.4 28.7 8.0
+ 2A5 10.2 9.9 16.8
+ 2A6 47.3 32.1 42.4
+ 2A7 8.5 22.3 3.9
+ 2A8 1.7 2.9 1.4
+ 2A9 14.3 10.1 27.8
+ 2A10 24.7 15.1 1.3
+ 2A11 40.4 55.4 48.2
+ 2A12 12.5 28.6 6.6
+ 2A13 17.0 12.5 15.7
+ 2A14 14.6 16.9 11.6
+ 2A15 35.4 36.8 29.1
+ 2A16 11.2 14.4 7.2
+ 2A17 8.1 22.0 12.6
+ 2A18 14.7 14.8 43.4
+ 2A19 52.6 34.1 36.1
+ 2B1 8.2 21.5 3.7
+ 2B2 40.1 55.9 5.0
+ 2B3 8.5 8.6 35.2
+ 2B4 23.3 16.1 34.6
+ 2B5 66.3 74.2 52.1
+ 2B6 66.5 70.5 66.1
+ 2B7 7.9 7.3 31.5
+ 2B8 23.4 40.5 20.0
+ 2B9 53.1 55.4 36.6
+ 2B10 23.4 30.2 26.5
+ 2B11 7.7 20.8 3.7
+ 2B12 13.5 11.6 32.2
+ 2B13 65.4 74.1 61.6
+ 2B14 34.7 21.0 33.0
+ 2B15 32.4 16.3 4.5
+ 2B16 44.5 39.0 18.5
+ 2B17 39.8 22.5 5.0
+ 2B18 45.2 26.2 19.4
+ 2B19 7.2 7.7 35.3
+ 2C1 42.8 48.7 62.0
+ 2C2 2.4 5.9 1.8
+ 2C3 20.1 26.5 5.2
+ 2C4 13.8 30.3 9.9
+ 2C5 12.2 9.3 29.9
+ 2C6 23.7 15.2 31.0
+ 2C7 21.9 39.4 13.3
+ 2C8 67.5 58.5 45.1
+ 2C9 20.1 13.5 30.7
+ 2C10 14.3 7.0 6.2
+ 2C11 45.5 59.1 51.0
+ 2C12 71.1 79.0 57.3
+ 2C13 7.1 7.8 36.9
+ 2C14 81.9 84.9 66.1
+ 2C15 7.1 6.1 27.2
+ 2C16 2.8 1.8 12.5
+ 2C17 7.6 8.6 1.2
+ 2C18 13.3 16.4 27.7
+ 2C19 59.2 68.5 4.0
+ 2D1 24.7 15.9 35.5
+ 2D2 27.6 17.5 15.1
+ 2D3 10.0 8.5 31.6
+ 2D4 1.8 2.0 6.8
+ 2D5 7.6 20.5 3.8
+ 2D6 1.3 1.6 1.1
+ 2D7 67.9 74.5 4.7
+ 2D8 37.8 40.3 56.9
+ 2D9 21.7 29.5 9.7
+ 2D10 24.5 27.3 22.3
+ 2D11 8.6 7.3 3.6
+ 2D12 8.1 11.8 14.9
+ 2D13 14.5 7.6 2.0
+ 2D14 17.5 13.6 35.9
+ 2D15 26.0 16.5 1.2
+ 2D16 37.5 20.6 5.1
+ 2D17 76.8 74.9 62.0
+ 2D18 73.7 79.1 41.9
+ 2D19 42.6 25.1 4.4
diff --git a/scanin/ColorCheckerSG.ti2 b/scanin/ColorCheckerSG.ti2
index 7459061..239b9e6 100644
--- a/scanin/ColorCheckerSG.ti2
+++ b/scanin/ColorCheckerSG.ti2
@@ -1,284 +1,163 @@
-CTI3
+CTI2
-DESCRIPTOR "Argyll Calibration Target chart information 3"
-ORIGINATOR "Argyll target"
-CREATED "Thu Feb 04 12:14:29 2010"
-KEYWORD "DEVICE_CLASS"
-DEVICE_CLASS "INPUT"
-KEYWORD "COLOR_REP"
-COLOR_REP "XYZ_RGB"
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+ORIGINATOR "Argyll printtarg"
+CREATED "Mon Feb 10 15:05:27 2014"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
-KEYWORD "STDEV_R"
-KEYWORD "STDEV_G"
-NUMBER_OF_FIELDS 10
+COLOR_REP "RGB"
+STEPS_IN_PASS 10
+PASSES_IN_STRIPS2 14
+STRIP_INDEX_PATTERN "A-Z, A-Z"
+PATCH_INDEX_PATTERN "@-9,0-9;01-99"
+INDEX_ORDER "STRIP_THEN_PATCH"
+
+NUMBER_OF_FIELDS 8
BEGIN_DATA_FORMAT
-SAMPLE_ID XYZ_X XYZ_Y XYZ_Z RGB_R RGB_G RGB_B STDEV_R STDEV_G STDEV_B
+SAMPLE_ID SAMPLE_LOC XYZ_X XYZ_Y XYZ_Z RGB_R RGB_G RGB_B
END_DATA_FORMAT
-NUMBER_OF_SETS 264
+NUMBER_OF_SETS 140
BEGIN_DATA
-A01 3.8500 3.2200 1.9000 3.0870 1.9150 1.9568 0.18288 0.33530 0.13814
-A02 4.8900 3.2700 1.6000 4.3780 1.1194 1.5620 0.18986 0.21677 0.15053
-A03 5.8700 3.3100 1.3300 7.0969 0.79829 1.4596 0.19608 0.13702 0.21648
-A04 6.3000 3.3800 1.1900 9.3444 0.79154 1.6415 0.24898 0.11159 0.21239
-A05 13.010 11.440 7.6400 14.232 7.8664 9.0240 0.51082 0.34461 0.40609
-A06 16.140 11.990 6.8100 19.112 4.9827 7.4008 0.27379 0.27636 0.24485
-A07 19.350 12.410 6.0600 24.550 2.9139 6.6589 0.44040 0.23921 0.36013
-A08 20.410 11.970 5.3000 28.200 1.9757 5.6575 0.32681 0.17783 0.34406
-A09 43.500 42.810 32.650 50.412 41.562 43.136 0.83769 0.58646 0.66130
-A10 45.580 42.370 30.950 52.491 37.167 40.121 0.65668 0.68089 0.75167
-A11 48.990 43.200 29.900 55.546 34.358 38.456 0.89084 0.72144 0.46689
-A12 50.730 44.020 29.960 59.252 33.923 39.172 0.67792 0.64492 0.71595
-A13 74.460 78.760 66.060 86.999 87.136 83.095 0.84067 0.78370 1.0173
-A14 75.660 76.420 64.080 88.257 85.809 81.940 0.97591 0.87575 0.93144
-A15 78.360 81.340 65.410 89.349 87.424 79.630 0.80575 0.84750 0.90746
-A16 70.520 73.300 59.160 83.248 81.172 76.884 0.59765 0.53177 0.91515
-A17 74.980 75.980 60.690 86.615 83.456 77.766 0.59041 0.64935 0.85237
-A18 72.850 77.300 60.250 85.072 85.370 78.761 0.67171 0.77803 0.78435
-A19 73.090 75.520 64.540 85.077 84.325 81.725 0.60827 0.53488 0.74148
-B01 3.4700 3.0800 1.4100 2.9819 1.8666 1.5474 0.25109 0.26023 0.14749
-B02 4.4100 3.2500 0.90000 3.9091 1.1519 0.44191 0.19422 0.17547 0.17939
-B03 5.0400 3.2300 0.58000 5.7842 0.78053 0.49340 0.39093 0.14767 0.25096
-B04 5.1900 3.1100 0.47000 6.2788 0.70721 0.41772 0.082907 0.18786 0.25207
-B05 13.360 11.590 5.5600 14.926 7.8469 6.2059 0.44744 0.41222 0.43440
-B06 15.970 12.030 3.6900 19.562 5.8030 4.2553 0.47005 0.19252 0.20287
-B07 19.200 12.490 2.2000 25.891 4.1954 2.6920 0.33271 0.22817 0.18918
-B08 19.730 11.520 1.1700 29.809 2.8266 1.9401 0.23472 0.24036 0.14395
-B09 42.190 41.840 29.340 52.125 42.714 40.345 0.71433 0.70374 0.66837
-B10 44.830 42.170 25.930 54.839 39.132 35.238 0.62084 0.61210 0.58037
-B11 48.060 42.900 23.010 60.127 37.706 33.524 0.63887 0.38462 0.62824
-B12 49.630 43.080 21.340 63.922 37.324 32.146 0.65762 0.54522 0.68989
-B13 66.210 72.540 64.610 81.667 84.767 81.706 0.65741 0.59295 0.68550
-B14 70.160 67.100 60.330 84.214 77.614 79.176 0.57243 0.69736 0.83505
-B15 75.460 78.690 51.580 87.872 84.913 72.334 0.64511 0.86763 0.77954
-B16 57.470 59.580 47.660 65.637 62.374 61.374 0.46048 0.54234 0.88766
-B17 68.330 66.450 49.050 80.849 69.402 66.741 0.47062 0.59840 0.78706
-B18 63.890 70.290 51.300 75.219 79.157 68.777 0.46400 0.45401 0.74257
-B19 61.120 62.160 59.790 74.928 72.212 78.002 0.52358 0.56321 0.65812
-C01 4.9700 4.7500 1.9800 3.8530 2.8861 1.9553 0.22700 0.21393 0.14122
-C02 5.1800 4.6500 1.2300 4.3282 2.3874 0.79270 0.23735 0.24096 0.13415
-C03 5.5100 4.5800 0.71000 4.8509 1.9934 0.37347 0.30081 0.24896 0.16563
-C04 5.7700 4.6100 0.67000 5.4652 2.2904 0.39892 0.31940 0.40663 0.17898
-C05 24.570 23.440 10.140 29.971 21.188 14.074 0.87441 0.65043 0.60853
-C06 28.100 24.640 5.2200 35.224 19.484 6.2233 0.47051 0.51996 0.34475
-C07 31.150 25.280 2.2000 43.555 21.569 1.7662 0.53328 0.28476 0.22826
-C08 30.850 23.680 1.3500 47.906 23.705 0.73860 0.48852 0.54401 0.30082
-C09 49.160 49.360 32.370 61.372 52.131 41.915 1.0230 0.96228 0.93947
-C10 51.720 50.720 26.530 66.081 50.197 35.277 0.52582 0.59072 0.68577
-C11 55.240 53.140 21.930 73.019 53.527 32.275 0.44506 0.61523 0.51984
-C12 56.870 53.620 18.460 76.306 55.256 27.858 0.73837 0.62107 0.67223
-C13 57.680 65.650 62.700 69.094 79.718 80.057 0.50745 0.49506 0.65851
-C14 63.460 56.660 55.490 79.979 64.212 75.539 0.48047 0.70668 0.61269
-C15 73.000 76.110 40.780 87.834 83.405 60.764 0.46451 0.49319 0.94645
-C16 44.730 46.380 36.800 49.238 47.428 48.251 0.66946 0.56694 0.71058
-C17 60.640 55.730 38.100 77.490 58.018 53.328 0.50391 0.73108 0.76100
-C18 52.150 60.270 41.500 59.790 70.951 55.734 0.51624 0.54134 0.69219
-C19 48.130 49.180 54.380 55.359 55.873 71.348 0.69989 0.65714 0.84068
-D01 4.1900 4.4100 1.9300 3.1562 3.1899 2.0240 0.14406 0.17903 0.20820
-D02 4.4800 4.7200 1.2400 3.1439 3.1237 0.90907 0.22921 0.19312 0.19845
-D03 4.5500 4.7800 0.80000 3.1884 3.4386 0.76835 0.18973 0.19251 0.14068
-D04 4.3200 4.5300 0.78000 2.7510 3.7222 0.39598 0.089835 0.21097 0.093653
-D05 27.330 28.550 12.950 32.935 30.788 16.103 0.86272 0.76614 1.0290
-D06 28.680 30.040 7.2500 34.121 32.521 9.2587 0.39709 0.61832 0.39734
-D07 29.510 31.010 3.4100 36.086 34.806 2.1211 0.45752 0.42772 0.32549
-D08 27.550 28.440 1.8300 37.395 33.673 0.41712 0.48746 0.39838 0.24261
-D09 56.060 58.190 38.210 68.806 62.355 48.849 0.83407 1.0243 1.0103
-D10 56.030 58.460 30.020 69.259 58.718 33.748 0.64690 0.51168 0.69310
-D11 56.200 59.330 24.440 73.375 62.236 30.616 0.61702 0.52252 0.65243
-D12 56.190 59.410 19.140 77.878 67.860 28.599 0.75670 0.62150 0.58932
-D13 48.210 57.420 59.530 51.811 71.459 76.862 0.52665 0.65682 0.77453
-D14 58.180 49.140 51.360 72.528 46.885 68.418 0.52499 0.49346 0.72705
-D15 70.980 73.730 33.630 87.340 80.456 47.511 0.58420 0.59197 0.74605
-D16 34.310 35.730 28.220 36.385 34.641 36.216 0.65565 0.55419 0.71008
-D17 54.270 47.530 29.580 71.607 44.334 41.932 0.46944 0.43555 0.66646
-D18 41.670 50.640 32.280 40.678 55.829 39.983 0.43992 0.47148 0.62583
-D19 36.950 37.820 48.090 37.649 36.082 58.334 0.42908 0.54659 0.83641
-E01 4.1500 4.7500 2.0300 3.1080 3.5881 2.3054 0.15860 0.18960 0.21718
-E02 4.0000 4.9800 1.3700 2.2371 3.5825 0.94616 0.25476 0.27294 0.19591
-E03 3.3000 4.4900 0.86000 1.6523 4.0563 0.38062 0.19385 0.38560 0.11779
-E04 3.1100 4.3000 0.86000 1.5621 5.4761 0.39158 0.26069 0.52827 0.12416
-E05 13.110 14.900 7.0600 15.304 17.657 10.409 0.47522 0.71252 0.51942
-E06 12.260 15.230 4.1800 12.178 18.905 5.5227 0.25140 0.45664 0.32497
-E07 11.530 15.570 2.2700 11.698 21.930 1.9527 0.26015 0.27007 0.21988
-E08 9.6900 13.740 1.5100 10.276 19.833 0.79976 0.39423 0.37372 0.23614
-E09 39.150 42.080 27.330 45.518 46.666 38.440 0.69913 0.70519 0.71247
-E10 37.430 41.510 22.230 44.807 49.208 32.547 0.55033 0.61108 0.60908
-E11 36.990 42.500 18.850 43.914 51.799 27.847 0.33881 0.53443 0.59872
-E12 36.400 42.580 16.270 43.530 52.579 24.028 0.42317 0.40277 0.79064
-E13 39.970 49.810 56.150 39.429 62.735 72.585 0.51788 0.70956 0.61542
-E14 52.080 41.070 46.360 60.752 30.200 56.615 0.61389 0.53882 0.50726
-E15 68.710 70.760 26.450 86.100 76.861 38.303 0.41619 0.79801 0.68629
-E16 25.700 26.970 21.280 27.203 25.514 27.365 0.37071 0.36979 0.64204
-E17 48.530 40.600 22.000 63.064 33.698 32.716 0.65833 0.49787 0.51247
-E18 31.620 40.820 23.350 33.628 51.020 34.670 0.45510 0.54658 0.59089
-E19 31.190 31.190 43.400 29.013 27.025 51.220 0.47563 0.55117 0.57962
-F01 1.5100 1.9100 1.0600 0.027596 0.75636 0.74985 0.15629 0.19236 0.22766
-F02 1.2900 2.0400 0.98000 4.9390e-004 1.0482 0.39366 0.027695 0.20025 0.047727
-F03 1.1600 2.0900 0.82000 1.2211e-003 1.3702 0.39338 0.055216 0.20402 0.055216
-F04 1.1400 2.0400 0.80000 5.2010e-004 1.8140 0.39216 0.028412 0.19742 8.7191e-017
-F05 6.5300 8.2500 5.1300 6.0620 8.7613 6.3749 0.21856 0.39993 0.34077
-F06 5.6100 8.6600 4.3800 5.0928 12.540 5.5351 0.32257 0.22932 0.31753
-F07 4.6000 8.7700 3.7000 3.9791 14.933 5.5371 0.22839 0.40306 0.31189
-F08 3.4500 7.6300 2.7800 3.1943 13.637 5.0607 0.18371 0.31217 0.28611
-F09 37.800 41.070 30.910 42.311 46.542 44.099 0.66414 0.71461 0.48054
-F10 35.920 40.760 29.030 37.090 45.514 41.038 0.54192 0.47361 0.49637
-F11 35.420 41.990 29.070 33.769 46.586 39.188 0.63863 0.44377 0.74150
-F12 34.000 41.800 28.000 32.661 47.456 39.230 0.38028 0.53728 0.61597
-F13 32.130 42.120 51.990 33.383 57.669 70.984 0.45695 0.68345 0.74883
-F14 45.720 33.340 40.770 54.515 21.176 49.435 0.62848 0.60201 0.59089
-F15 66.260 67.290 19.650 85.509 74.348 30.963 0.34004 0.66164 0.72944
-F16 17.020 18.070 14.400 18.492 17.628 19.716 0.41175 0.41125 0.55653
-F17 41.590 32.530 15.160 55.337 23.031 22.717 0.32869 0.58391 0.55775
-F18 26.260 35.260 18.810 29.664 47.253 28.577 0.65266 0.49301 0.47012
-F19 24.300 23.600 37.480 19.299 17.238 43.015 0.51151 0.45280 0.37522
-G01 2.3100 3.0000 2.2700 0.84520 2.3174 1.9294 0.18283 0.18185 0.16146
-G02 2.0000 3.2100 2.5800 0.75456 2.8979 2.5428 0.15935 0.25240 0.20833
-G03 1.6600 3.2100 2.7500 0.76882 3.1767 2.7895 0.13653 0.18762 0.18509
-G04 1.5800 3.0300 2.6000 0.72753 3.5401 3.1385 0.21153 0.23805 0.12733
-G05 8.9900 11.080 8.7900 8.6417 12.633 13.013 0.23258 0.38272 0.51760
-G06 7.6800 11.300 9.5600 6.0762 14.162 13.630 0.34219 0.48961 0.37830
-G07 6.5200 11.500 10.200 4.7151 15.595 15.675 0.18999 0.25121 0.34355
-G08 5.5000 10.850 10.550 3.9310 15.708 18.487 0.17658 0.18808 0.38867
-G09 38.290 41.750 33.450 41.221 46.682 47.377 0.47434 0.65583 0.69760
-G10 35.830 41.160 34.110 34.960 46.653 48.630 0.43230 0.33577 0.68757
-G11 34.560 41.830 35.630 33.586 49.866 51.379 0.54290 0.54558 0.79591
-G12 33.690 42.140 36.700 33.047 50.497 52.510 0.47475 0.63324 0.64506
-G13 25.950 35.680 48.000 25.821 49.453 66.662 0.37812 0.43551 0.68026
-G14 40.600 27.620 36.140 49.315 12.855 43.923 0.59407 0.51249 0.39980
-G15 63.720 63.630 14.350 85.087 71.090 23.531 0.42910 0.70922 0.51323
-G16 10.850 11.820 9.5800 12.480 12.126 12.956 0.45159 0.26832 0.47760
-G17 37.230 27.640 11.620 47.527 14.544 15.337 0.27575 0.21502 0.45406
-G18 20.280 28.970 14.150 22.086 39.214 21.499 0.22375 0.42080 0.58054
-G19 17.700 16.740 31.700 11.092 8.9799 34.605 0.30961 0.25432 0.34654
-H01 2.5600 3.0400 2.9200 1.0797 1.6510 2.5225 0.19148 0.29249 0.31180
-H02 2.3400 3.2000 4.1200 0.75605 1.9921 3.9184 0.20879 0.18831 0.34399
-H03 2.1200 3.2800 5.4300 1.1188 2.6942 5.7632 0.18331 0.31552 0.43690
-H04 2.0600 3.1800 5.2900 0.95250 3.6569 9.1081 0.19606 0.26991 0.32976
-H05 10.070 11.600 11.240 8.3322 11.376 15.622 0.28376 0.42701 0.40381
-H06 9.0100 11.680 14.810 5.4932 11.765 20.056 0.091608 0.41488 0.57575
-H07 8.2200 12.000 19.420 4.9770 14.064 28.422 0.20715 0.32326 0.42487
-H08 7.2500 11.550 21.450 3.2684 15.675 34.112 0.21933 0.26892 0.44285
-H09 39.250 42.310 36.810 41.417 46.807 52.636 0.40783 0.63180 0.70186
-H10 37.580 41.850 40.370 37.620 47.457 56.394 0.40780 0.38262 0.60753
-H11 37.160 43.070 45.790 35.702 50.905 63.199 0.32421 0.46580 0.63305
-H12 36.270 43.780 49.470 33.495 51.722 65.912 0.49238 0.80083 0.50501
-H13 21.470 30.780 44.220 17.358 41.175 60.322 0.53191 0.33884 0.71172
-H14 36.490 23.350 32.380 42.559 7.4512 37.794 0.63662 0.37435 0.45301
-H15 61.580 60.550 10.950 83.946 67.032 17.125 0.47747 0.68565 0.68924
-H16 8.2100 8.7100 6.9100 7.7370 6.7073 7.1914 0.30311 0.32664 0.38434
-H17 33.040 23.260 8.3800 41.945 9.7770 9.4041 0.36608 0.27977 0.29341
-H18 16.220 24.350 10.410 14.161 31.400 14.036 0.50870 0.42853 0.33315
-H19 12.860 11.840 26.820 6.7641 4.8816 27.846 0.21234 0.35512 0.43660
-I01 4.2200 4.4400 5.2800 2.5804 3.1209 5.5388 0.19793 0.22097 0.23814
-I02 4.3500 4.4800 8.3600 2.1950 2.9540 8.2511 0.21318 0.37273 0.15204
-I03 4.4000 4.4400 11.940 1.5551 2.3277 13.781 0.13059 0.32101 0.44139
-I04 4.4800 4.5800 12.170 1.5183 2.7011 16.873 0.18903 0.18775 0.54146
-I05 15.150 15.780 15.230 14.098 13.280 19.482 0.38631 0.35696 0.61921
-I06 14.560 15.120 19.520 11.398 11.740 26.460 0.39190 0.31696 0.53900
-I07 14.370 14.810 24.480 9.0951 10.558 31.378 0.31653 0.47750 0.40616
-I08 14.110 14.760 30.030 8.8994 12.525 38.791 0.19577 0.41303 0.47520
-I09 41.030 42.580 36.940 44.643 44.074 50.860 0.49120 0.38131 0.77241
-I10 40.850 42.230 40.730 43.872 44.287 55.517 0.47835 0.37431 0.74007
-I11 40.860 42.330 45.050 42.122 43.554 59.117 0.48773 0.61376 0.75436
-I12 41.310 42.730 47.770 40.877 43.038 60.455 0.52027 0.78243 0.89880
-I13 17.260 25.930 40.230 11.385 33.626 53.134 0.24543 0.46746 0.49207
-I14 32.660 19.630 28.810 37.259 3.1300 31.648 0.53636 0.22763 0.56347
-I15 59.370 57.180 7.7900 81.619 61.582 10.428 0.45678 0.75637 0.50761
-I16 4.9700 5.3200 4.3200 4.1247 4.2743 4.4333 0.25062 0.28647 0.22229
-I17 28.620 18.880 5.4800 37.742 6.2496 5.7060 0.30537 0.26137 0.31918
-I18 11.580 18.980 7.2500 10.598 26.684 8.8664 0.26978 0.44054 0.42495
-I19 9.5800 8.3400 22.870 4.2150 3.2891 23.893 0.21095 0.25111 0.44678
-I20 0.45000 0.40000 0.33000 0.39216 0.39216 0.54897 8.7185e-017 8.7185e-017 0.19577
-I21 2.2800 1.7800 0.98000 1.5621 0.40380 0.78485 0.17869 0.12419 0.10123
-I22 2.3700 1.9500 0.85000 1.6757 0.52953 0.77981 0.20785 0.19502 0.097289
-J01 2.1500 1.9000 2.6000 0.80586 0.46230 2.3504 0.14574 0.18600 0.061302
-J02 2.5700 2.0000 4.7200 0.88254 0.50462 3.8319 0.23987 0.27408 0.28547
-J03 2.9300 1.9500 8.1000 1.1741 0.79211 7.0759 0.059711 0.10088 0.41081
-J04 3.1500 1.9200 10.760 1.1579 0.78634 9.8197 0.13923 0.054971 0.30540
-J05 11.730 11.600 11.810 10.434 9.0014 15.080 0.27064 0.18087 0.39725
-J06 12.980 11.930 16.190 9.8203 6.5823 18.989 0.42140 0.31577 0.43052
-J07 13.910 12.070 20.950 9.0486 5.3905 24.287 0.43191 0.32612 0.46685
-J08 14.010 11.590 24.350 9.4663 4.4573 26.676 0.46513 0.26033 0.44412
-J09 40.750 41.220 36.340 46.279 42.745 50.219 0.48484 0.49432 0.71791
-J10 41.260 41.070 39.740 46.208 41.530 53.967 0.39057 0.37860 0.69962
-J11 42.630 41.680 44.510 46.276 39.907 57.241 0.36909 0.43099 0.77240
-J12 44.020 41.780 49.250 46.523 38.842 60.774 0.60050 0.54935 0.80146
-J13 13.820 21.690 35.980 6.4384 27.059 47.284 0.27804 0.44682 0.53798
-J14 28.870 16.330 25.080 33.360 1.4880 26.700 0.54686 0.35986 0.50147
-J15 56.040 52.290 4.9700 79.215 55.635 5.6027 0.36036 0.67586 0.40739
-J16 2.4600 2.6300 2.2900 2.0271 1.9425 2.1126 0.22979 0.25009 0.22276
-J17 24.040 14.750 3.1500 32.513 3.3788 3.9462 0.38941 0.25099 0.22979
-J18 8.1200 14.490 4.5500 6.8312 20.787 5.0280 0.26878 0.48921 0.37476
-J19 5.9800 4.7900 17.760 1.9349 1.4360 18.258 0.25534 0.19476 0.43841
-J20 8.2600 5.3700 1.0400 9.0085 1.2119 1.6117 0.45009 0.24630 0.21888
-J21 11.520 7.8100 1.6200 15.322 3.1307 1.6660 0.28794 0.15307 0.22993
-J22 14.670 10.720 2.6000 19.118 4.7445 3.3211 0.27061 0.23207 0.23572
-K01 5.6300 4.7000 4.8600 3.1669 2.3147 4.3372 0.16578 0.17296 0.16002
-K02 6.7400 4.5800 7.2300 4.7712 1.7242 5.8628 0.19822 0.36800 0.19901
-K03 8.0400 4.4800 9.7300 7.0830 0.83482 8.6422 0.34393 0.17784 0.40049
-K04 9.3900 4.7600 11.790 9.3140 0.83699 11.430 0.19932 0.17903 0.39652
-K05 16.660 15.390 14.440 15.838 10.461 17.251 0.32001 0.40528 0.46694
-K06 18.720 15.180 18.230 18.124 6.6879 21.403 0.40410 0.17228 0.49710
-K07 21.560 15.500 22.970 21.965 5.3109 25.015 0.24740 0.23832 0.38336
-K08 23.000 15.020 25.370 24.105 3.1608 26.801 0.32492 0.16608 0.48978
-K09 42.500 42.020 36.050 47.117 40.740 49.022 0.53629 0.37845 0.70340
-K10 44.550 41.630 39.710 49.817 36.865 51.366 0.65172 0.52763 0.69630
-K11 47.190 41.960 44.030 49.582 31.706 51.769 0.59677 0.49442 0.61865
-K12 49.900 43.140 47.210 49.812 27.011 52.296 0.66045 0.55640 0.61863
-K13 10.610 17.440 31.240 4.4300 21.053 41.922 0.22576 0.30726 0.65920
-K14 24.840 13.190 21.000 29.807 0.40689 21.925 0.51521 0.12873 0.23282
-K15 53.120 48.050 3.1900 76.497 50.546 1.9742 0.42392 0.89083 0.22911
-K16 1.0500 1.1400 1.1300 0.37611 0.38958 0.78350 0.16012 0.11365 0.056938
-K17 19.930 11.340 1.6700 28.212 1.8825 1.9270 0.20132 0.19250 0.18652
-K18 5.3000 10.470 2.7300 4.6984 16.487 2.7171 0.27557 0.20947 0.35113
-K19 3.9500 2.7600 13.940 1.1640 0.78992 13.028 0.14201 0.087689 0.38375
-K20 30.610 26.430 11.040 37.280 17.799 14.056 0.42873 0.33930 0.49948
-K21 34.910 29.600 11.780 46.591 23.876 16.346 0.59613 0.61207 0.58881
-K22 38.950 34.570 18.400 50.441 29.451 25.122 0.41109 0.46425 0.53273
-L01 3.8800 3.1200 2.3200 2.3754 1.1903 2.4650 0.23374 0.24751 0.21411
-L02 4.9300 3.2000 2.6900 3.5670 0.87669 2.4249 0.19064 0.19083 0.21057
-L03 5.7500 3.1400 3.0200 6.2627 0.88805 2.7596 0.15419 0.19237 0.13238
-L04 7.3100 3.7900 3.4000 12.143 0.79340 5.0822 0.36514 0.10735 0.18096
-L05 13.290 11.540 9.3900 13.257 6.7371 11.007 0.53413 0.39748 0.52457
-L06 16.220 11.730 10.320 17.565 4.3606 11.749 0.41329 0.23326 0.22842
-L07 19.950 12.080 12.060 23.621 1.9646 12.957 0.36857 0.073970 0.44540
-L08 20.790 11.310 12.010 27.319 1.1467 14.145 0.39539 0.24605 0.48567
-L09 43.220 42.090 33.780 49.604 40.742 46.106 0.73537 0.46689 0.65281
-L10 45.520 41.880 34.650 52.432 36.546 46.285 0.70127 0.47543 0.81335
-L11 49.040 42.870 35.980 52.918 31.732 45.276 0.56655 0.49649 0.63589
-L12 51.030 43.830 37.780 56.056 30.451 46.847 0.71159 0.54349 0.47579
-L13 7.4500 12.770 25.590 3.1210 15.741 36.868 0.16774 0.41923 0.54315
-L14 21.260 10.760 17.730 25.639 0.67463 17.297 0.33435 0.23099 0.28299
-L15 49.450 43.120 2.1400 71.709 42.401 0.77056 0.63981 0.77745 0.15935
-L16 0.47000 0.49000 0.50000 0.39216 0.39242 0.44227 8.7191e-017 0.020117 0.17760
-L17 16.040 8.4900 0.78000 22.615 0.77695 0.80931 0.41597 0.098510 0.17603
-L18 2.9100 6.5000 1.3900 2.3795 10.578 0.82736 0.41720 0.36726 0.25065
-L19 2.5000 1.4500 10.280 0.87774 0.87456 9.0192 0.19100 0.19050 0.23749
-L20 38.700 33.980 20.860 46.392 26.795 27.748 0.70761 0.62342 0.62702
-L21 39.360 35.230 21.230 49.082 30.312 29.444 0.78808 0.53733 0.63082
-L22 41.360 38.770 23.510 49.490 34.663 31.428 0.65330 0.41753 0.60905
-GS00 79.470 82.510 69.040 94.066 92.950 89.438 0.92099 0.93414 1.0465
-GS01 72.620 74.940 59.170 83.147 81.219 77.715 0.78271 0.68705 0.94766
-GS02 63.150 65.110 51.570 72.917 70.218 68.669 1.6258 1.2707 1.2120
-GS03 54.720 56.510 45.030 62.183 59.826 59.273 1.1706 0.93329 0.94511
-GS04 48.100 49.810 39.240 54.449 52.983 53.093 0.94040 0.74898 0.81106
-GS05 42.220 43.640 34.450 46.328 44.248 45.944 0.67400 0.50032 0.83337
-GS06 37.330 38.700 30.500 38.317 37.642 39.414 0.73797 0.55911 0.80063
-GS07 32.380 33.610 26.110 33.430 32.555 34.311 0.65078 0.68590 0.53545
-GS08 27.560 28.700 22.110 28.329 27.391 29.319 0.58496 0.47730 0.62283
-GS09 22.500 23.400 17.990 24.816 23.504 25.107 0.34653 0.55560 0.46821
-GS10 18.770 19.550 14.830 19.965 19.162 21.933 0.53943 0.57276 0.50639
-GS11 15.480 16.080 12.040 16.404 15.001 17.243 0.45210 0.41568 0.49656
-GS12 12.690 13.290 9.9800 12.196 12.177 13.695 0.44316 0.26670 0.48288
-GS13 10.350 10.810 7.9700 9.2053 9.3069 10.577 0.20471 0.20663 0.38564
-GS14 8.3900 8.7700 6.3700 6.8434 6.6000 6.6948 0.44020 0.30795 0.33660
-GS15 6.4500 6.7900 4.9700 5.0530 5.1099 5.4164 0.19533 0.41922 0.22533
-GS16 4.9500 5.1800 3.7000 3.5418 3.5969 4.0009 0.21349 0.20376 0.24671
-GS17 3.5800 3.8200 2.7600 2.2466 2.3553 2.3640 0.20655 0.13937 0.14287
-GS18 2.7600 2.8900 2.0600 1.1077 1.1790 1.5754 0.28160 0.25904 0.24353
-GS19 1.9700 2.0800 1.4500 0.35943 0.40395 0.79579 0.18424 0.11867 0.11747
-GS20 1.2200 1.3100 0.98000 0.23507 0.31297 0.70239 0.19729 0.21133 0.18880
-GS21 1.0000 1.0500 0.74000 0.38400 0.38523 0.77548 0.10266 0.10537 0.10605
-GS22 0.87000 0.89000 0.65000 0.39216 0.39216 0.74886 8.7126e-017 8.7126e-017 0.16598
-GS23 0.34000 0.32000 0.32000 0.39226 0.39237 0.43006 0.012929 0.018274 0.16840
+1 "A01" 88.2480 87.5060 67.6240 99.2353 99.7118 99.5554
+2 "A02" 0.794510 0.785690 0.624230 3.14714 4.68603 5.08608
+3 "A03" 18.3810 18.1460 14.1200 54.0301 65.6038 60.7520
+4 "A04" 88.6800 87.9440 68.0980 99.0451 99.4536 99.2556
+5 "A05" 0.824100 0.810630 0.656110 3.10665 4.43021 4.90322
+6 "A06" 18.4400 18.2040 14.1760 52.4803 64.1539 59.5981
+7 "A07" 88.6450 87.9000 67.9470 98.8924 98.9556 99.1026
+8 "A08" 0.832010 0.821550 0.664060 3.16261 3.84029 4.35848
+9 "A09" 18.1170 17.8910 13.9510 49.3671 61.6291 56.5615
+10 "A10" 88.8710 88.1260 68.0820 98.6642 99.1385 99.0660
+11 "B01" 18.0200 17.7950 13.9090 55.0686 66.0592 61.9429
+12 "B02" 13.9470 7.22560 8.26540 68.1681 0.0450395 56.4805
+13 "B03" 35.6280 27.8520 32.8420 88.8315 59.9937 99.6552
+14 "B04" 10.6720 5.28080 15.2480 43.1040 0.0502000 87.5639
+15 "B05" 14.4130 15.7890 39.3970 21.7750 70.1273 99.9547
+16 "B06" 20.6780 26.2380 36.8920 35.2551 99.0188 77.5504
+17 "B07" 1.45030 2.34850 2.56120 2.04420 12.9928 18.2739
+18 "B08" 18.0380 25.7190 27.0400 32.3543 99.9619 64.7212
+19 "B09" 3.37980 3.27430 1.57890 8.38116 9.89768 6.55200
+20 "B10" 18.4840 18.2440 14.1910 51.0152 63.0221 58.4410
+21 "C01" 0.825050 0.814760 0.657280 3.45013 5.01294 5.40847
+22 "C02" 4.57810 3.29160 5.61620 12.9428 4.08519 38.0010
+23 "C03" 14.5950 11.3080 24.2900 43.8628 27.8035 99.9476
+24 "C04" 2.74320 2.49490 8.91480 0.0841099 5.05299 57.3589
+25 "C05" 22.9170 25.7880 40.2490 47.8425 89.5040 94.9187
+26 "C06" 1.83670 2.40490 5.02520 0.0925296 8.61708 42.0348
+26 "C07" 26.4450 26.6910 42.3540 60.2448 80.4263 99.6501
+28 "C08" 10.2540 16.9170 17.2820 20.7339 88.7631 52.2998
+29 "C09" 19.0520 27.2060 12.2700 41.1843 99.8507 35.2397
+30 "C10" 0.805310 0.795850 0.639850 3.03575 4.08577 4.67877
+31 "D01" 88.4950 87.7520 67.9080 99.5510 99.5464 99.5571
+32 "D02" 61.9490 61.4510 55.8040 96.4784 96.5058 99.5547
+33 "D03" 70.8290 63.5300 49.3270 99.7724 92.6467 98.0025
+34 "D04" 55.9600 62.6940 49.9140 89.0089 99.9676 94.1003
+35 "D05" 71.1690 64.5570 44.5670 99.8200 93.1762 96.0933
+36 "D06" 58.4250 62.2180 28.8560 95.2652 97.4714 85.5067
+37 "D07" 38.5680 30.1250 8.72090 97.7247 60.9183 25.4159
+38 "D08" 38.9330 32.3110 15.6350 94.9899 67.4615 67.8546
+39 "D09" 9.70690 17.2520 8.69020 18.0329 94.3103 15.6986
+40 "D10" 88.8520 88.1030 68.1490 98.8895 98.9418 99.0172
+41 "E01" 18.1400 17.9140 13.9700 56.1278 67.1050 63.4896
+42 "E02" 8.91530 6.95450 2.01090 42.6753 18.3928 0.240737
+43 "E03" 39.6620 29.4150 2.05650 99.8589 57.9921 0.763152
+44 "E04" 3.84910 2.21640 16.3130 0.0356264 1.61558 77.2429
+45 "E05" 88.5440 87.7950 67.9070 99.2218 99.5992 99.5562
+46 "E06" 0.797860 0.786020 0.637060 3.24176 4.79711 5.19033
+47 "E07" 57.9520 50.1120 24.1350 99.8375 83.3955 73.6909
+48 "E08" 55.6470 45.0930 20.4680 99.9381 76.3745 66.0755
+49 "E09" 1.80460 2.87160 1.55130 4.48621 18.0239 4.30997
+50 "E10" 18.2860 18.0540 14.0520 52.1381 63.9931 59.5867
+51 "F01" 0.821450 0.811590 0.652140 3.57770 5.15708 5.53341
+52 "F02" 37.5450 31.1590 14.8630 96.5601 68.3501 70.3025
+53 "F03" 9.33780 7.45630 25.3510 10.9434 23.1229 99.7024
+54 "F04" 12.1560 19.3000 4.12860 23.1756 99.6011 0.0467819
+55 "F05" 54.5560 53.7060 42.1400 94.0193 93.9462 95.0190
+56 "F06" 6.40720 6.33990 5.06690 17.0382 27.4615 23.1311
+57 "F07" 35.9410 31.6060 12.5440 92.1715 71.6310 56.7871
+58 "F08" 37.1160 32.6870 16.7870 90.7079 71.9484 62.7050
+59 "F09" 17.6330 26.2060 16.5150 36.1091 99.9776 44.7211
+60 "F10" 0.817450 0.803300 0.648070 3.03016 4.52847 4.93133
+61 "G01" 88.1180 87.3790 67.6390 99.6063 99.6546 99.6378
+62 "G02" 14.1420 14.4220 21.7790 31.5235 64.4645 88.2405
+63 "G03" 27.0730 16.1500 6.52890 99.3019 18.8709 29.9070
+64 "G04" 19.3760 9.31950 1.23360 92.7481 0.0514771 0.996714
+65 "G05" 33.4270 32.9730 25.9370 79.6111 83.8506 83.8771
+66 "G06" 11.0640 10.9460 8.65770 33.3576 46.6792 41.8190
+67 "G07" 16.1500 13.5220 3.95020 63.4164 39.5547 3.47786
+68 "G08" 37.6610 32.4480 16.8480 92.7905 70.2031 67.4679
+69 "G09" 21.4030 28.6380 6.93640 38.7589 99.9778 0.496405
+70 "G10" 88.7630 88.0110 68.0300 99.1885 99.2266 99.3112
+71 "H01" 18.2340 18.0030 14.0320 57.6571 67.9088 64.2915
+72 "H02" 7.93780 10.0280 2.21420 16.0406 60.3414 0.0759039
+73 "H03" 5.32950 3.13280 7.61040 18.4523 0.0274370 48.8589
+74 "H04" 58.2760 57.3920 3.84380 97.3325 94.4934 8.98711
+75 "H05" 18.0560 17.8320 13.9270 55.2642 65.9668 62.1343
+76 "H06" 27.8670 27.4770 21.6560 72.6082 79.1552 77.6922
+77 "H07" 40.9840 36.1270 18.8500 94.1035 76.7796 72.9008
+78 "H08" 38.1290 32.7720 16.0850 93.5800 70.8410 66.5429
+79 "H09" 10.9120 18.9050 3.25920 18.3400 97.6540 1.11200
+80 "H10" 18.3150 18.0830 14.0770 54.1252 65.7287 61.1352
+81 "I01" 0.877970 0.866490 0.692530 3.89803 5.52321 5.87104
+82 "I02" 20.9640 18.5090 28.0310 63.1732 61.5508 99.2533
+83 "I03" 33.5760 40.9120 5.28710 76.4298 99.9653 9.91792
+84 "I04" 28.7570 16.5770 19.4170 97.5162 15.7443 99.9554
+85 "I05" 8.34090 8.24580 6.46760 26.2127 37.6943 32.9267
+86 "I06" 47.5260 46.8020 36.7430 91.1191 92.1693 92.7183
+87 "I07" 18.5620 14.2840 2.53620 71.7667 36.8616 0.0762142
+88 "I08" 10.9170 8.92160 2.27380 49.8294 27.4643 0.0776073
+89 "I09" 17.4380 28.5650 5.55330 34.9025 99.9410 12.7946
+90 "I10" 0.821180 0.807980 0.647830 3.47476 5.04339 5.42659
+91 "J01" 88.4510 87.7100 67.8900 99.8550 99.9501 99.9252
+92 "J02" 28.2480 36.7910 28.9770 62.3789 99.9741 75.3109
+93 "J03" 46.4790 40.8160 3.05390 99.6210 80.8061 2.48062
+94 "J04" 10.7330 14.6700 25.4470 21.5610 81.2289 77.0705
+95 "J05" 1.94760 1.93530 1.62720 4.71988 8.24480 7.82566
+96 "J06" 72.4300 71.6040 56.5980 98.1204 98.3388 99.1073
+97 "J07" 39.0010 31.8440 12.6630 96.0770 67.9382 46.5024
+98 "J08" 41.2900 34.6190 13.3580 96.8660 72.4588 54.8591
+99 "J09" 34.2630 30.1940 5.39700 90.2234 70.2202 0.0623386
+100 "J10" 88.6890 87.9420 67.9450 99.2152 99.2801 99.5654
+101 "K01" 18.2870 18.0550 14.0940 59.0025 69.1409 65.5487
+102 "K02" 69.7990 64.7750 36.6120 99.6822 95.7093 91.7473
+103 "K03" 65.6850 71.9500 50.5420 96.8438 99.8905 97.2996
+104 "K04" 65.7350 62.3550 54.3800 98.3442 95.6648 99.6471
+105 "K05" 56.6400 60.8890 55.7810 93.0084 99.2612 98.7282
+106 "K06" 40.8830 40.3150 31.7710 87.4846 90.0455 89.9846
+107 "K07" 14.7360 14.5610 11.2750 47.0421 59.2067 53.9164
+108 "K08" 2.93200 2.88900 2.29030 7.41163 11.4541 9.79805
+109 "K09" 26.2580 30.2340 4.53580 63.1341 93.2221 0.0298406
+110 "K10" 18.2730 18.0420 14.0570 55.2930 66.4439 62.3838
+111 "L01" 0.862840 0.850990 0.693220 3.87962 5.48970 5.85651
+112 "L02" 6.16360 3.50110 1.81220 38.1729 0.0962079 3.80448
+113 "L03" 26.3380 13.4420 1.40110 99.7165 4.53211 1.36954
+114 "L04" 38.5470 28.0920 19.9310 99.9731 55.0042 83.5153
+115 "L05" 39.7740 29.2290 14.6560 99.9422 58.7798 61.5525
+116 "L06" 46.5510 31.0860 1.68400 99.8180 54.7591 3.14563
+117 "L07" 40.3200 44.8880 2.28100 81.9478 98.4938 0.688775
+118 "L08" 30.8790 30.5350 4.30920 83.9547 79.4768 0.0391914
+119 "L09" 34.3480 43.5170 4.20490 69.3966 99.9270 0.0658071
+120 "L10" 0.800670 0.788840 0.635170 3.97289 5.83698 5.98220
+121 "M01" 18.1930 17.9660 14.0100 59.6309 69.7719 66.1588
+122 "M02" 23.9480 12.4740 6.90150 99.7706 4.70147 59.4602
+123 "M03" 4.91740 2.88340 3.24780 28.1391 0.561666 23.5497
+124 "M04" 22.8350 11.3090 2.24090 99.8063 1.68667 20.7720
+125 "M05" 37.8580 20.9420 3.22960 99.8275 25.8631 6.21660
+126 "M06" 68.6210 59.7530 4.77180 97.8760 92.5321 9.30162
+127 "M07" 62.1430 60.5650 3.45590 96.8719 96.3609 10.1197
+128 "M08" 36.4040 42.0820 3.08240 80.3325 98.4745 0.724150
+129 "M09" 3.84880 2.97780 0.821780 16.4467 9.88207 4.80164
+130 "M10" 18.2420 18.0100 14.0270 56.4231 67.0989 63.5167
+131 "N01" 88.2290 87.5100 67.7730 99.7306 99.7388 99.7304
+132 "N02" 18.2350 18.0070 14.0330 58.4655 68.6862 65.0329
+133 "N03" 0.902820 0.890040 0.724140 3.68406 5.33264 5.63854
+134 "N04" 88.5680 87.8170 67.9670 99.6812 99.9152 99.8513
+135 "N05" 18.1220 17.8970 13.9580 56.8631 66.9076 63.7330
+136 "N06" 0.910530 0.896090 0.727430 3.61138 5.17412 5.50048
+137 "N07" 88.7080 87.9570 67.9660 99.5758 99.5768 99.5772
+138 "N08" 18.1980 17.9690 14.0030 56.1060 66.6952 63.0654
+139 "N09" 0.843350 0.831020 0.672600 3.93895 5.79967 5.81986
+140 "N10" 88.8180 88.0710 68.1240 99.5289 99.6025 99.5746
END_DATA
diff --git a/scanin/Jamfile b/scanin/Jamfile
index 2cb05fb..203ba2a 100644
--- a/scanin/Jamfile
+++ b/scanin/Jamfile
@@ -13,6 +13,7 @@ Samples = it8.cht ColorChecker.cht ColorChecker.cie ColorCheckerDC.cht ColorChec
ColorCheckerPassport.cht ColorCheckerPassport.cie
QPcard_201.cht QPcard_201.cie QPcard_202.cht QPcard_202.cie CMP_DT_003.cht
CMP_Digital_Target-4.cht CMP_Digital_Target-4.ti2 CMP_Digital_Target-4.cie
+ CMP_Digital_Target-7.cht
LaserSoftDCPro.cht SpyderChecker.cht SpyderChecker.cie
SpyderChecker24.cht SpyderChecker24.cie ;
diff --git a/scanin/afiles b/scanin/afiles
index 90097e6..cd76a75 100644
--- a/scanin/afiles
+++ b/scanin/afiles
@@ -25,6 +25,7 @@ CMP_DT_003.cht
CMP_Digital_Target-4.cht
CMP_Digital_Target-4.ti2
CMP_Digital_Target-4.cie
+CMP_Digital_Target-7.cht
LaserSoftDCPro.cht
SpyderChecker.cht
SpyderChecker.cie
diff --git a/spectro/IntsLib_Readme.txt b/spectro/IntsLib_Readme.txt
index 7d9fb0c..c8df3d3 100644
--- a/spectro/IntsLib_Readme.txt
+++ b/spectro/IntsLib_Readme.txt
@@ -3,17 +3,6 @@ create the instlib.zip archive.
To build it:
-If you are on Linux or OS X, you first need to
-build libusb 1.0A, ie::
-
- cd libusb1
- sh autogen.sh
- make
- cp libusb/libusb-1.0A.a .
- cd ..
-
-(The libraries are pre-built for MSWin)
-
To build the standalone instrument lib, you
need to edit the Makefile to #include the appropriate
Makefile.XXX for your operating system, and then
diff --git a/spectro/Jamfile b/spectro/Jamfile
index 9eb292f..94a2f70 100644
--- a/spectro/Jamfile
+++ b/spectro/Jamfile
@@ -127,7 +127,7 @@ if $(USE_DEMOINST) = true && [ GLOB [ NormPaths . ] : demoinst.c ] {
INST_SRCS += demoinst.c ;
}
-Library libinst : inst.c insttypes.c icoms.c disptechs.c rspec.c $(INST_SRCS) ;
+Library libinst : inst.c insttypes.c icoms.c disptechs.c rspec.c xrga.c $(INST_SRCS) ;
# Display access library
ObjectKeep mongoose.c ;
diff --git a/spectro/Makefile.SA b/spectro/Makefile.SA
index 2d57742..5913126 100644
--- a/spectro/Makefile.SA
+++ b/spectro/Makefile.SA
@@ -39,12 +39,12 @@ WIN_STDHDRS = $(INCFLAG)usb$(SLASH)driver
all:: libinst$(SUFLIB) libinstappsup$(SUFLIB) spotread$(SUFEXE) oeminst$(SUFEXE)
INSTHEADERS = dtp20.h dtp22.h dtp41.h dtp51.h dtp92.h ss.h ss_imp.h i1disp.h i1d3.h i1pro.h i1pro_imp.h munki.h munki_imp.h hcfr.h huey.h colorhug.h spyd2.h specbos.h kleink10.h
-INSOBJS = dtp20$(SUFOBJ) dtp22$(SUFOBJ) dtp41$(SUFOBJ) dtp51$(SUFOBJ) dtp92$(SUFOBJ) ss$(SUFOBJ) ss_imp$(SUFOBJ) i1disp$(SUFOBJ) i1d3$(SUFOBJ) i1pro$(SUFOBJ) i1pro_imp$(SUFOBJ) munki$(SUFOBJ) munki_imp$(SUFOBJ) hcfr$(SUFOBJ) huey$(SUFOBJ) colorhug$(SUFOBJ) spyd2$(SUFOBJ) specbos$(SUFOBJ) kleink10$(SUFOBJ)
+INSOBJS = dtp20$(SUFOBJ) dtp22$(SUFOBJ) dtp41$(SUFOBJ) dtp51$(SUFOBJ) dtp92$(SUFOBJ) ss$(SUFOBJ) ss_imp$(SUFOBJ) i1disp$(SUFOBJ) i1d3$(SUFOBJ) i1pro$(SUFOBJ) i1pro_imp$(SUFOBJ) munki$(SUFOBJ) munki_imp$(SUFOBJ) hcfr$(SUFOBJ) huey$(SUFOBJ) colorhug$(SUFOBJ) spyd2$(SUFOBJ) specbos$(SUFOBJ) kleink10$(SUFOBJ) ex1$(SUFOBJ) smcube$(SUFOBJ)
-HEADERS = pollem.h conv.h aglob.h hidio.h icoms.h inst.c inst.h insttypeinst.h insttypes.h disptechs.h $(INSTHEADERS) usbio.h xspect.h rspl1.h sort.h xdg_bds.h ccss.h ccmx.h pars.h cgats.h instappsup.h usb$(SLASH)driver$(SLASH)driver_api.h
+HEADERS = pollem.h conv.h sa_conv.h aglob.h hidio.h icoms.h inst.c inst.h insttypeinst.h insttypes.h disptechs.h rspec.h xrga.h $(INSTHEADERS) usbio.h xspect.h rspl1.h sort.h xdg_bds.h ccss.h ccmx.h pars.h cgats.h instappsup.h usb$(SLASH)driver$(SLASH)driver_api.h
# libinst objects
-OBJS = conv$(SUFOBJ) aglob$(SUFOBJ) inst$(SUFOBJ) numsup$(SUFOBJ) rspl1$(SUFOBJ) icoms$(SUFOBJ) usbio$(SUFOBJ) hidio$(SUFOBJ) insttypes$(SUFOBJ) disptechs$(SUFOBJ) pollem$(SUFOBJ) xspect$(SUFOBJ) xdg_bds$(SUFOBJ) ccss$(SUFOBJ) ccmx$(SUFOBJ) pars$(SUFOBJ) cgats$(SUFOBJ) $(INSOBJS)
+OBJS = conv$(SUFOBJ) sa_conv$(SUFOBJ) aglob$(SUFOBJ) inst$(SUFOBJ) numsup$(SUFOBJ) rspl1$(SUFOBJ) icoms$(SUFOBJ) usbio$(SUFOBJ) hidio$(SUFOBJ) insttypes$(SUFOBJ) disptechs$(SUFOBJ) rspec$(SUFOBJ) xrga$(SUFOBJ) pollem$(SUFOBJ) xspect$(SUFOBJ) xdg_bds$(SUFOBJ) ccss$(SUFOBJ) ccmx$(SUFOBJ) pars$(SUFOBJ) cgats$(SUFOBJ) $(INSOBJS)
# instrument library
@@ -52,6 +52,9 @@ OBJS = conv$(SUFOBJ) aglob$(SUFOBJ) inst$(SUFOBJ) numsup$(SUFOBJ) rspl1$(SUFOBJ)
conv$(SUFOBJ): conv.c $(HEADERS)
$(CC) conv.c
+sa_conv$(SUFOBJ): sa_conv.c $(HEADERS)
+ $(CC) sa_conv.c
+
aglob$(SUFOBJ): aglob.c $(HEADERS)
$(CC) aglob.c
@@ -76,6 +79,12 @@ hidio$(SUFOBJ): hidio.c $(HEADERS)
insttypes$(SUFOBJ): insttypes.c $(HEADERS)
$(CC) insttypes.c
+rspec$(SUFOBJ): rspec.c $(HEADERS)
+ $(CC) rspec.c
+
+xrga$(SUFOBJ): xrga.c $(HEADERS)
+ $(CC) xrga.c
+
disptechs$(SUFOBJ): disptechs.c $(HEADERS)
$(CC) disptechs.c
@@ -148,6 +157,12 @@ specbos$(SUFOBJ): specbos.c $(HEADERS)
kleink10$(SUFOBJ): kleink10.c $(HEADERS)
$(CC) kleink10.c
+ex1$(SUFOBJ): ex1.c $(HEADERS)
+ $(CC) ex1.c
+
+smcube$(SUFOBJ): smcube.c $(HEADERS)
+ $(CC) smcube.c
+
oemarch$(SUFOBJ): oemarch.c $(HEADERS)
$(CC) oemarch.c
diff --git a/spectro/afiles b/spectro/afiles
index 984bac5..8891ce7 100644
--- a/spectro/afiles
+++ b/spectro/afiles
@@ -26,6 +26,7 @@ mongoose.c
insttypes.h
insttypes.c
insttypeinst.h
+dev.h
inst.c
inst.h
disptechs.h
@@ -87,8 +88,12 @@ spec2cie.c
average.c
rspec.h
rspec.c
+xrga.h
+xrga.c
conv.h
conv.c
+sa_conv.h
+sa_conv.c
aglob.h
aglob.c
xdg_bds.h
diff --git a/spectro/average.c b/spectro/average.c
index 5a8fb3f..e961262 100644
--- a/spectro/average.c
+++ b/spectro/average.c
@@ -23,6 +23,7 @@
*/
+
#undef DEBUG
#define verbo stdout
@@ -34,10 +35,15 @@
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
+#include "sort.h"
#include "cgats.h"
#include "xicc.h"
#include "insttypes.h"
+static double average(double *vals, int nvals);
+static double median(double *vals, int nvals);
+static void geommed(double res[3], double vals[][3], int nvals);
+
void usage(char *diag, ...) {
int i;
fprintf(stderr,"Average or merge values in .ti3 like files, Version %s\n",ARGYLL_VERSION_STR);
@@ -52,6 +58,10 @@ void usage(char *diag, ...) {
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
fprintf(stderr,"usage: average [-options] input1.ti3 input2.ti3 ... output.ti3\n");
fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -e Median rather than average\n");
+ fprintf(stderr," -g Geometric Median of PCS in encoded space\n");
+ fprintf(stderr," -L Geometric Median of PCS in L*a*b* space\n");
+ fprintf(stderr," -X Geometric Median of PCS in XYZ space\n");
fprintf(stderr," -m Merge rather than average\n");
fprintf(stderr," input1.ti3 First input file\n");
fprintf(stderr," input2.ti3 Second input file\n");
@@ -69,6 +79,8 @@ struct _inpinfo {
int main(int argc, char *argv[]) {
int fa,nfa; /* current argument we're looking at */
int verb = 0;
+ int domedian = 0; /* Median rather than average */
+ int dogeom = 0; /* Do geometric median of PCS, 2 = Lab, 3 = PCS */
int domerge = 0; /* Merge rather than average */
int ninps = 0; /* Number of input files */
@@ -78,10 +90,12 @@ int main(int argc, char *argv[]) {
cgats_set_elem *setel; /* Array of set value elements */
int *flags; /* Point to destination of set */
- int nchan; /* Number of device channels */
+ int nchan = 0; /* Number of device channels */
int chix[ICX_MXINKS]; /* Device chanel indexes */
- int pcsix[3]; /* PCS chanel indexes */
- int isLab = 0;
+ int npcs = 0;
+
+ int haspcs[2] = { 0 }; /* Has Lab, XYZ */
+ int pcsix[3][3]; /* Lab, XYZ chanel indexes */
int i, j, n;
@@ -110,13 +124,33 @@ int main(int argc, char *argv[]) {
if (argv[fa][1] == '?')
usage("Usage requested");
+ /* Median */
+ else if (argv[fa][1] == 'e') {
+ domedian = 1;
+ }
+
+ /* Geometric Median of PCS */
+ else if (argv[fa][1] == 'g') {
+ dogeom = 1;
+ }
+
+ /* Geometric Median of PCS in L*a*b* */
+ else if (argv[fa][1] == 'L') {
+ dogeom = 2;
+ }
+
+ /* Geometric Median of PCS in XYZ */
+ else if (argv[fa][1] == 'X') {
+ dogeom = 3;
+ }
+
/* Merge */
- else if (argv[fa][1] == 'm' || argv[fa][1] == 'M') {
+ else if (argv[fa][1] == 'm') {
domerge = 1;
}
/* Verbosity */
- else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ else if (argv[fa][1] == 'v') {
verb = 1;
}
@@ -192,8 +226,9 @@ int main(int argc, char *argv[]) {
ocg->add_field(ocg, n, inps[0].c->t[n].fsym[i], inps[0].c->t[n].ftype[i]);
}
+ /* If more than one file, must be merging or averaging between files */
if (ninps > 1) {
- /* Duplicate all of the data */
+ /* Duplicate all of the data or first file to output file */
if ((setel = (cgats_set_elem *)malloc(
sizeof(cgats_set_elem) * inps[0].c->t[n].nfields)) == NULL)
error("Malloc failed!");
@@ -207,11 +242,11 @@ int main(int argc, char *argv[]) {
}
/* Figure out the indexes of the device channels */
- {
+ if (inps[0].c->find_kword(inps[0].c, 0, "COLOR_REP") < 0) {
+ warning("Input file '%s' doesn't contain keyword COLOR_REP", inps[0].name);
+ } else {
int ti;
char *buf;
- char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
- char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
char *outc;
int nmask;
char *bident;
@@ -227,13 +262,6 @@ int main(int argc, char *argv[]) {
error("COLOR_REP '%s' invalid", inps[0].c->t[0].kdata[ti]);
*outc++ = '\000';
- if (strcmp(outc, "XYZ") == 0) {
- isLab = 0;
- } else if (strcmp(outc, "LAB") == 0) {
- isLab = 1;
- } else
- error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", inps[0].c->t[0].kdata[ti]);
-
if ((nmask = icx_char2inkmask(buf)) == 0) {
error ("File '%s' keyword COLOR_REP has unknown device value '%s'",inps[0].name,buf);
}
@@ -256,19 +284,32 @@ int main(int argc, char *argv[]) {
error ("Field %s is wrong type",fname);
chix[j] = ii;
}
-
- /* Find PCS fields */
- for (j = 0; j < 3; j++) {
- int ii;
-
- if ((ii = inps[0].c->find_field(inps[0].c, 0, isLab ? labfname[j] : xyzfname[j])) < 0)
- error ("Input file doesn't contain field %s",isLab ? labfname[j] : xyzfname[j]);
- if (inps[0].c->t[0].ftype[ii] != r_t)
- error ("Field %s is wrong type",isLab ? labfname[j] : xyzfname[j]);
- pcsix[j] = ii;
+ }
+
+ /* Figure out the indexes of the PCS channels, if any */
+ {
+ int npcs;
+ char *fname[2][3] = { { "LAB_L", "LAB_A", "LAB_B" },
+ { "XYZ_X", "XYZ_Y", "XYZ_Z" } };
+
+ /* For Lab and XYZ */
+ for (j = 0; j < 2; j++) {
+ for (npcs = 0; npcs < 3; npcs++) {
+ int ii;
+
+ if ((ii = inps[0].c->find_field(inps[0].c, 0, fname[j][npcs])) < 0)
+ break; /* Try next or give up */
+
+ if (inps[0].c->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname[j][npcs]);
+ pcsix[j][npcs] = ii;
+ }
+ if (npcs == 3)
+ haspcs[j] = 1;
}
- free(bident);
}
+ if (!haspcs[0] && !haspcs[1])
+ warning("No PCS fields found - hope that's OK!");
if (!domerge && verb) {
printf("Averaging the following fields:");
@@ -294,7 +335,8 @@ int main(int argc, char *argv[]) {
printf("\n");
}
- /* Get ready to add more values to output */
+ /* Get ready to add more values to output, */
+ /* for merging or averaging within one file. */
if ((setel = (cgats_set_elem *)malloc(
sizeof(cgats_set_elem) * inps[0].c->t[0].nfields)) == NULL)
error("Malloc failed!");
@@ -302,13 +344,24 @@ int main(int argc, char *argv[]) {
/* If averaging values within the one file */
if (ninps == 1) {
int *valdone;
- double npatches;
- int k;
+ int npat;
+ double *vlist;
+ double (*v3list)[3] = NULL;
+ int k, e;
n = 0; /* Output set index */
if ((valdone = (int *)calloc(inps[0].c->t[0].nsets, sizeof(int))) == NULL)
error("Malloc failed!");
+ if ((vlist = (double *)calloc(inps[0].c->t[0].nsets, sizeof(double))) == NULL)
+ error("Malloc failed!");
+
+ if (dogeom && (haspcs[0] || haspcs[1])) {
+ if ((v3list = (double (*)[3])calloc(inps[0].c->t[0].nsets, 3 * sizeof(double))) == NULL)
+ error("Malloc failed!");
+ }
+
+ /* For each patch */
for (i = 0; i < inps[0].c->t[0].nsets; i++) {
if (valdone[i])
@@ -316,49 +369,8 @@ int main(int argc, char *argv[]) {
inps[0].c->get_setarr(inps[0].c, 0, i, setel);
ocg->add_setarr(ocg, 0, setel);
- npatches = 1.0;
-
- /* Locate and patches with matching device values */
- for (k = i+1; k < inps[0].c->t[0].nsets; k++) {
-
- /* Check if the device values match */
- for (j = 0; j < nchan; j++) {
- double diff;
-
- diff = *((double *)inps[0].c->t[0].fdata[i][chix[j]])
- - *((double *)inps[0].c->t[0].fdata[k][chix[j]]);
-
- if (fabs(diff) > 0.001) {
- break;
- }
- }
- if (j < nchan) {
- continue;
- }
- /* Add all the non-device real field values */
- for (j = 0; j < inps[0].c->t[0].nfields; j++) {
- int jj;
-
- /* Only real types */
- if (inps[0].c->t[0].ftype[j] != r_t)
- continue;
-
- /* Not device channels */
- for (jj = 0; jj < nchan; jj++) {
- if (chix[jj] == j)
- break;
- }
- if (jj < nchan)
- continue;
-
- *((double *)ocg->t[0].fdata[n][j])
- += *((double *)inps[0].c->t[0].fdata[k][j]);
- }
- npatches++;
- valdone[k] = 1;
- }
- /* Average them out */
+ /* For each non-device real field values */
for (j = 0; j < inps[0].c->t[0].nfields; j++) {
int jj;
@@ -374,20 +386,102 @@ int main(int argc, char *argv[]) {
if (jj < nchan)
continue;
- *((double *)ocg->t[0].fdata[n][j]) /= npatches;
+ /* Locate any patches (including starting patch) with matching device values */
+ npat = 0;
+ for (k = i; k < inps[0].c->t[0].nsets; k++) {
+
+ /* Check if the device values match */
+ for (e = 0; e < nchan; e++) {
+ double diff;
+
+ diff = *((double *)inps[0].c->t[0].fdata[i][chix[e]])
+ - *((double *)inps[0].c->t[0].fdata[k][chix[e]]);
+
+ if (fabs(diff) > 0.001) {
+ break;
+ }
+ }
+ if (e < nchan) {
+ continue;
+ }
+
+ vlist[npat++] = *((double *)inps[0].c->t[0].fdata[k][j]);
+ valdone[k] = 1;
+ }
+ if (domedian)
+ *((double *)ocg->t[0].fdata[n][j]) = median(vlist, npat);
+ else
+ *((double *)ocg->t[0].fdata[n][j]) = average(vlist, npat);
+ }
+
+ /* Override per-component average/median if PCS Geometric Median */
+ if (dogeom && (haspcs[0] || haspcs[1])) {
+ double res[3];
+
+ /* For Lab and XYZ */
+ for (j = 0; j < 2; j++) {
+
+ if (haspcs[j] == 0)
+ continue;
+
+ /* Locate any patches (including starting patch) with matching device values */
+ npat = 0;
+ for (k = i; k < inps[0].c->t[0].nsets; k++) {
+
+ /* Check if the device values match */
+ for (e = 0; e < nchan; e++) {
+ double diff;
+
+ diff = *((double *)inps[0].c->t[0].fdata[i][chix[e]])
+ - *((double *)inps[0].c->t[0].fdata[k][chix[e]]);
+
+ if (fabs(diff) > 0.001) {
+ break;
+ }
+ }
+ if (e < nchan) {
+ continue;
+ }
+
+ v3list[npat][0] = *((double *)inps[0].c->t[0].fdata[k][pcsix[j][0]]);
+ v3list[npat][1] = *((double *)inps[0].c->t[0].fdata[k][pcsix[j][1]]);
+ v3list[npat][2] = *((double *)inps[0].c->t[0].fdata[k][pcsix[j][2]]);
+
+ if (j == 0 && dogeom == 3) /* Lab and want XYZ */
+ icmLab2XYZ(&icmD50_100, v3list[npat], v3list[npat]);
+ else if (j == 1 && dogeom == 2) /* XYZ and want Lab */
+ icmXYZ2Lab(&icmD50_100, v3list[npat], v3list[npat]);
+
+ npat++;
+ }
+ geommed(res, v3list, npat);
+
+ if (j == 0 && dogeom == 3)
+ icmXYZ2Lab(&icmD50_100, res, res);
+ else if (j == 1 && dogeom == 2)
+ icmLab2XYZ(&icmD50_100, res, res);
+
+ *((double *)ocg->t[0].fdata[n][pcsix[j][0]]) = res[0];
+ *((double *)ocg->t[0].fdata[n][pcsix[j][1]]) = res[1];
+ *((double *)ocg->t[0].fdata[n][pcsix[j][2]]) = res[2];
+ }
}
n++; /* One more output set */
}
+ if (v3list != NULL)
+ free(v3list);
+ free(vlist);
free(valdone);
/* Averaging patches between identical files, */
/* or concatenating (merging) several files */
} else {
- /* Process all the other input files */
+
+ /* Check/process all the other input files */
for (n = 1; n < ninps; n++) {
- /* Check all the fields match */
+ /* Check all the fields match the first file */
if (inps[0].c->t[0].nfields != inps[n].c->t[0].nfields)
error ("File '%s' has %d fields, file '%s has %d",
inps[n].name, inps[n].c->t[0].nfields, inps[0].name, inps[0].c->t[0].nfields);
@@ -405,15 +499,15 @@ int main(int argc, char *argv[]) {
}
} else { /* Averaging */
- /* Check the number of values matches */
+
+ /* Check the number of patches matches the first file */
if (inps[0].c->t[0].nsets != inps[n].c->t[0].nsets)
error ("File '%s' has %d sets, file '%s has %d",
inps[n].name, inps[n].c->t[0].nsets, inps[0].name, inps[0].c->t[0].nsets);
-
- /* Add the numeric field values to corresponding output */
+ /* For all the patches: */
for (i = 0; i < inps[n].c->t[0].nsets; i++) {
- /* Check that the device values match */
+ /* Check that the device values match the first file */
for (j = 0; j < nchan; j++) {
double diff;
diff = *((double *)inps[0].c->t[0].fdata[i][chix[j]])
@@ -423,53 +517,100 @@ int main(int argc, char *argv[]) {
error ("File '%s' set %d has field '%s' value that differs from '%s'",
inps[n].name, i+1, inps[n].c->t[0].fsym[j], inps[0].name);
}
-
- /* Add all the non-device real field values */
- for (j = 0; j < inps[0].c->t[0].nfields; j++) {
- int jj;
-
- /* Only real types */
- if (inps[0].c->t[0].ftype[j] != r_t)
- continue;
-
- /* Not device channels */
- for (jj = 0; jj < nchan; jj++) {
- if (chix[jj] == j)
- break;
- }
- if (jj < nchan)
- continue;
-
- *((double *)ocg->t[0].fdata[i][j])
- += *((double *)inps[n].c->t[0].fdata[i][j]);
- }
}
}
}
-
- /* If averaging, divide out the number of files */
+
+ /* If averaging */
if (!domerge) {
+ int npat;
+ double *vlist;
+ double (*v3list)[3] = NULL;
+
+ if ((vlist = (double *)calloc(ninps, sizeof(double))) == NULL)
+ error("Malloc failed!");
+
+ if (dogeom && (haspcs[0] || haspcs[1])) {
+ if ((v3list = (double (*)[3])calloc(inps[0].c->t[0].nsets, 3 * sizeof(double))) == NULL)
+ error("Malloc failed!");
+ }
+
+ /* For all the non-device real field values */
+ for (j = 0; j < inps[0].c->t[0].nfields; j++) {
+ int jj;
+
+ /* Only real types */
+ if (inps[0].c->t[0].ftype[j] != r_t)
+ continue;
+
+ /* Not device channels */
+ for (jj = 0; jj < nchan; jj++) {
+ if (chix[jj] == j)
+ break;
+ }
+ if (jj < nchan)
+ continue;
- for (i = 0; i < inps[n].c->t[0].nsets; i++) {
-
- for (j = 0; j < inps[0].c->t[0].nfields; j++) {
- int jj;
-
- /* Only real types */
- if (inps[0].c->t[0].ftype[j] != r_t)
- continue;
-
- /* Not device channels */
- for (jj = 0; jj < nchan; jj++) {
- if (chix[jj] == j)
- break;
+ /* For each patch */
+ for (i = 0; i < inps[n].c->t[0].nsets; i++) {
+
+ /* For all input files */
+ npat = 0;
+ for (n = 0; n < ninps; n++) {
+ vlist[npat++] = *((double *)inps[n].c->t[0].fdata[i][j]);
}
- if (jj < nchan)
- continue;
+
+ if (domedian)
+ *((double *)ocg->t[0].fdata[i][j]) = median(vlist, npat);
+ else
+ *((double *)ocg->t[0].fdata[i][j]) = average(vlist, npat);
+ }
+ }
+
+ /* Override per-component average/median if PCS Geometric Median */
+ if (dogeom && (haspcs[0] || haspcs[1])) {
+ double res[3];
+
+ /* For each patch */
+ for (i = 0; i < inps[n].c->t[0].nsets; i++) {
+
+ /* For Lab and XYZ */
+ for (j = 0; j < 2; j++) {
+
+ if (haspcs[j] == 0)
+ continue;
- *((double *)ocg->t[0].fdata[i][j]) /= (double)ninps;
+ /* For all input files */
+ npat = 0;
+ for (n = 0; n < ninps; n++) {
+ v3list[npat][0] = *((double *)inps[n].c->t[0].fdata[i][pcsix[j][0]]);
+ v3list[npat][1] = *((double *)inps[n].c->t[0].fdata[i][pcsix[j][1]]);
+ v3list[npat][2] = *((double *)inps[n].c->t[0].fdata[i][pcsix[j][2]]);
+
+ if (j == 0 && dogeom == 3) /* Lab and want XYZ */
+ icmLab2XYZ(&icmD50_100, v3list[npat], v3list[npat]);
+ else if (j == 1 && dogeom == 2) /* XYZ and want Lab */
+ icmXYZ2Lab(&icmD50_100, v3list[npat], v3list[npat]);
+
+ npat++;
+ }
+ geommed(res, v3list, npat);
+
+ if (j == 0 && dogeom == 3)
+ icmXYZ2Lab(&icmD50_100, res, res);
+ else if (j == 1 && dogeom == 2)
+ icmLab2XYZ(&icmD50_100, res, res);
+
+ *((double *)ocg->t[0].fdata[i][pcsix[j][0]]) = res[0];
+ *((double *)ocg->t[0].fdata[i][pcsix[j][1]]) = res[1];
+ *((double *)ocg->t[0].fdata[i][pcsix[j][2]]) = res[2];
+ }
}
}
+
+ if (v3list != NULL)
+ free(v3list);
+ free(vlist);
}
}
@@ -490,6 +631,69 @@ int main(int argc, char *argv[]) {
}
+static double average(double *vals, int nvals) {
+ double rv;
+ int i;
+
+ for (rv = 0.0, i = 0; i < nvals; i++)
+ rv += vals[i];
+
+ if (nvals > 0)
+ rv /= (double)nvals;
+
+ return rv;
+}
+
+static double median(double *vals, int nvals) {
+ if (nvals < 3)
+ return average(vals, nvals);
+
+#define HEAP_COMPARE(A,B) (A < B)
+ HEAPSORT(double,vals,nvals);
+
+ if ((nvals & 1) != 0)
+ return vals[nvals/2];
+ else
+ return 0.5 * (vals[nvals/2] + vals[nvals/2-1]);
+}
+/* Compute Geometric Median of PCS values */
+/* using Weiszfeld's algorithm. */
+static void geommed(double res[3], double vals[][3], int nvals) {
+ int i, j;
+
+ /* Start with mean value */
+ icmSet3(res, 0.0);
+ for (i = 0; i < nvals; i++)
+ icmAdd3(res, res, vals[i]);
+ icmScale3(res, res, 1.0/(double)nvals);
+
+//printf("\n~1 average = %f %f %f\n", res[0], res[1], res[2]);
+
+ /* Itterate to approach Geometric Mean */
+ for (j = 0; j < 20; j++) {
+ double tv[3], tt;
+ int k;
+
+ icmSet3(tv, 0.0);
+ tt = 0.0;
+ for (k = i = 0; i < nvals; i++) {
+ double norm = icmNorm33(vals[i], res);
+ if (norm < 1e-6)
+ continue;
+ tv[0] += vals[i][0]/norm;
+ tv[1] += vals[i][1]/norm;
+ tv[2] += vals[i][2]/norm;
+ tt += 1.0/norm;
+ k++;
+//printf("Norm = %f, tv = %f %f %f, tt = %f\n",norm, tv[0], tv[1], tv[2], tt);
+ }
+ if (k > 0)
+ icmScale3(res, tv, 1.0/tt);
+//printf("~1 res = %f %f %f\n", res[0], res[1], res[2]);
+ }
+
+//printf("~1 geomm = %f %f %f\n", res[0], res[1], res[2]);
+}
diff --git a/spectro/base64.c b/spectro/base64.c
index 388d121..8e07967 100644
--- a/spectro/base64.c
+++ b/spectro/base64.c
@@ -4,6 +4,9 @@
*
* Very simple & concise base64 encoder/decoder
*
+ */
+
+/*
* Author: Graeme W. Gill
*
* Copyright 2014, Graeme W. Gill
diff --git a/spectro/base64.h b/spectro/base64.h
index 726f20a..29ca140 100644
--- a/spectro/base64.h
+++ b/spectro/base64.h
@@ -1,9 +1,13 @@
+#ifndef BASE64_H
+
/*
* Argyll Color Correction System
*
* Very simple & concise base64 encoder/decoder
- *
+ */
+
+/*
* Author: Graeme W. Gill
*
* Copyright 2014, Graeme W. Gill
@@ -13,6 +17,9 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
/* The maximum encoded length given decoded length */
#define EBASE64LEN(len) (((len) * 4 + 2)/3)
@@ -30,4 +37,9 @@ void ebase64(int *dlen, char *dst, unsigned char *src, int slen);
/* We assume that the destination buffer is long enough at DBASE64LEN */
void dbase64(int *dlen, unsigned char *dst, char *src);
+#ifdef __cplusplus
+ }
+#endif
+#define BASE64_H
+#endif /* BASE64_H */
diff --git a/spectro/ccwin.c b/spectro/ccwin.c
index 1e9a18d..a89bc65 100644
--- a/spectro/ccwin.c
+++ b/spectro/ccwin.c
@@ -454,7 +454,7 @@ icmFile *ccwin_get_profile(dispwin *p, char *name, int mxlen) {
/* Change the window color. */
/* Return 1 on error, 2 on window being closed */
-/* inst_license, inst_licensenc or inst_tamper on licening problem */
+/* inst_license, inst_licensenc, inst_tamper or inst_syscompat on licening problem */
static int ccwin_set_color(
dispwin *p,
double r, double g, double b /* Color values 0.0 - 1.0 */
@@ -487,9 +487,9 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
/* For video encoding the extra bits of precision are created by bit shifting */
/* rather than scaling, so we need to scale the fp value to account for this. */
- if (p->pdepth > 8)
- p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->pdepth - 8)))
- /((1 << p->pdepth) - 1.0);
+ if (p->edepth > 8)
+ p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->edepth - 8)))
+ /((1 << p->edepth) - 1.0);
}
}
@@ -798,8 +798,11 @@ int ddebug /* >0 to print debug statements to stderr */
p->ncix = 1;
- p->pdepth = 8; /* Assume this by API */
- p->edepth = 8;
+ p->fdepth = 8; /* Assume this by API */
+ p->rdepth = p->fdepth; /* Assumed */
+ p->ndepth = p->rdepth; /* Assumed */
+ p->nent = 0; /* No ramdac */
+ p->edepth = 8; /* Assumed */
/* Basic object is initialised, so create connection to ChromeCast */
if ((ws = new_chws(cc_id, width, height, hoff, voff, verb, ddebug)) == NULL) {
diff --git a/spectro/ccxxmake.c b/spectro/ccxxmake.c
index 418affc..740eb0a 100644
--- a/spectro/ccxxmake.c
+++ b/spectro/ccxxmake.c
@@ -500,7 +500,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage(0,"Paramater expected following -W");
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -1441,11 +1441,12 @@ int main(int argc, char *argv[]) {
strcat(colname, ")");
}
if (description == NULL) {
- if ((description = malloc(strlen(colname) + strlen(displayname) + 4)) == NULL)
+ char *disp = displayname != NULL ? displayname : dtinfo->desc;
+ if ((description = malloc(strlen(colname) + strlen(disp) + 4)) == NULL)
error("Malloc failed");
strcpy(description, colname);
strcat(description, " & ");
- strcat(description, displayname);
+ strcat(description, disp);
}
if (refrmode < 0)
diff --git a/spectro/chartread.c b/spectro/chartread.c
index 9cf6c22..e1624e1 100644
--- a/spectro/chartread.c
+++ b/spectro/chartread.c
@@ -1,7 +1,8 @@
+/* Spectrometer/Colorimeter target test chart reader */
+
/*
* Argyll Color Correction System
- * Spectrometer/Colorimeter target test chart reader
*
* Author: Graeme W. Gill
* Date: 4/10/96
@@ -58,6 +59,11 @@
#define COMPORT 1 /* Default com port 1..4 */
+#undef TEST_EVENT_CALLBACK /* Report async event callbacks, and implement beep prompt there. */
+
+#undef USESTRDELTA /* [Und] Use patch delat's for correlation rather than match DE */
+ /* Doesn't seem to work as well. Why ? */
+
#ifdef __MINGW32__
# define WINVER 0x0500
#endif
@@ -69,22 +75,36 @@
#include <time.h>
#include <ctype.h>
#include <string.h>
+#ifndef SALONEINSTLIB
#include "copyright.h"
#include "aconfig.h"
-#include "cgats.h"
#include "numlib.h"
-#include "icc.h"
#include "xicc.h"
-#include "insttypes.h"
#include "conv.h"
+#include "ui.h"
+#include "icc.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#include "cgats.h"
+#include "rspl1.h"
+#include "xspect.h"
+#include "xcolorants.h"
+#include "xcal.h"
+#include "conv.h"
+#include "sa_conv.h"
+#endif /* SALONEINSTLIB */
+#include "cgats.h"
+#include "insttypes.h"
#include "icoms.h"
#include "inst.h"
#include "ccmx.h"
#include "ccss.h"
+#ifndef SALONEINSTLIB
#include "dispwin.h"
-#include "ui.h"
#include "ccast.h"
#include "dispsup.h"
+#endif /* !SALONEINSTLIB */
#include "alphix.h"
#include "sort.h"
#include "instappsup.h"
@@ -132,6 +152,24 @@ static double xyzLabDE(double ynorm, double *pat, double *ref) {
return icmLabDE(Lab1, Lab2);
}
+#ifdef USESTRDELTA
+/* Return the -ve correlation of the delta E's between steps */
+static double xyzLabcorr(double *pat0, double *ref0,
+ double *pat1, double *ref1) {
+ double p0[3], p1[3], pd[3];
+ double r0[3], r1[3], rd[3];
+
+ icmXYZ2Lab(&icmD50, p0, pat0);
+ icmXYZ2Lab(&icmD50, p1, pat1);
+ ICMSUB3(pd, p0, p1);
+ icmXYZ2Lab(&icmD50, r0, ref0);
+ icmXYZ2Lab(&icmD50, r1, ref1);
+ ICMSUB3(rd, r0, r1);
+
+ return -icmDot3(rd, pd);
+}
+#endif
+
/* A chart read color structure */
/* This can hold all representations simultaniously */
typedef struct {
@@ -169,6 +207,15 @@ static int b62_int(char *p) {
return rv;
}
+#ifdef TEST_EVENT_CALLBACK
+void test_event_callback(void *cntx, inst_event_type event) {
+ a1logd(g_log,0,"Got event_callback with 0x%x\n",event);
+
+ if (event == inst_event_scan_ready)
+ normal_beep();
+}
+#endif
+
/* Deal with an instrument error. */
/* Return 0 to retry, 1 to abort */
static int ierror(inst *it, inst_code ic) {
@@ -211,6 +258,8 @@ int displ, /* 1 = Use display emissive mode, 2 = display bright rel. */
/* 3 = display white rel. */
int dtype, /* Display type selection charater */
inst_opt_filter fe, /* Optional filter */
+xcalstd scalstd, /* X-Rite calibration standard to set */
+xcalstd *ucalstd, /* X-Rite calibration standard actually used */
int nocal, /* Disable initial calibration */
int disbidi, /* Disable automatic bi-directional strip recognition */
int highres, /* Use high res spectral mode */
@@ -224,6 +273,7 @@ int spectral, /* Generate spectral info flag */
int uvmode, /* ~~~ i1pro2 test mode ~~~ */
int accurate_expd, /* Expected values can be assumed to be accurate */
int emit_warnings, /* Emit warnings for wrong strip, unexpected value */
+int doplot, /* Plot each spectra in patch by patch mode */
a1log *log /* verb, debug & error log */
) {
inst *it = NULL;
@@ -251,6 +301,11 @@ a1log *log /* verb, debug & error log */
printf("Unknown, inappropriate or no instrument detected\n");
return -1;
}
+
+#ifdef TEST_EVENT_CALLBACK
+ it->set_event_callback(it, test_event_callback, (void *)it);
+#endif
+
/* Establish communications */
if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
printf("Establishing communications with instrument failed with message '%s' (%s)\n",
@@ -276,6 +331,24 @@ a1log *log /* verb, debug & error log */
return -1;
}
+ /* For reflective */
+ if (emis == 0 && trans == 0) {
+
+ /* set XRGA conversion */
+ if (scalstd != xcalstd_none) {
+ if ((rv = it->get_set_opt(it, inst_opt_set_xcalstd, scalstd)) != inst_ok) {
+ printf("Warning: Setting calibration standard not supported by instrument\n");
+ }
+ }
+
+ /* Get actual XRGA conversion */
+ if (ucalstd != NULL) {
+ if ((rv = it->get_set_opt(it, inst_opt_get_xcalstd, ucalstd)) != inst_ok) {
+ *ucalstd = xcalstd_none;
+ }
+ }
+ }
+
*atype = it->get_itype(it); /* Actual instrument type */
if (*atype != itype)
a1logv(log, 1, "Warning: chart is for %s, using instrument %s\n",inst_name(itype),inst_name(*atype));
@@ -297,8 +370,8 @@ a1log *log /* verb, debug & error log */
} else if (emis || displ) {
if (emis) {
- if (!IMODETST(cap, inst_mode_emis_spot)
- && !IMODETST(cap, inst_mode_emis_strip)) {
+ if (it->check_mode(it, inst_mode_emis_spot) != inst_ok
+ && it->check_mode(it, inst_mode_emis_strip) != inst_ok) {
printf("Need emissive spot or strip reading capability\n");
printf("and instrument doesn't support it\n");
it->del(it);
@@ -306,7 +379,7 @@ a1log *log /* verb, debug & error log */
}
} else {
/* Should we allow for non-adaptive mode ? */
- if (!IMODETST(cap, inst_mode_emis_spot)) {
+ if (it->check_mode(it, inst_mode_emis_spot) != inst_ok) {
printf("Need emissive reading capability\n");
printf("and instrument doesn't support it\n");
it->del(it);
@@ -314,7 +387,7 @@ a1log *log /* verb, debug & error log */
}
}
- } else {
+ } else { /* reflectance */
if (!IMODETST(cap, inst_mode_reflection)) {
printf("Need reflection spot, strip, xy or chart reading capability,\n");
printf("and instrument doesn't support it\n");
@@ -461,20 +534,17 @@ a1log *log /* verb, debug & error log */
/* Should look at instrument type & user spec ??? */
if (trans) {
- if (pbypatch && IMODETST(cap, inst_mode_trans_spot)
+ if (pbypatch
&& it->check_mode(it, inst_mode_trans_spot) == inst_ok) {
mode = inst_mode_trans_spot;
rmode = 0;
- } else if (IMODETST(cap, inst_mode_trans_chart)
- && it->check_mode(it, inst_mode_trans_chart) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_trans_chart) == inst_ok) {
mode = inst_mode_trans_chart;
rmode = 3;
- } else if (IMODETST(cap, inst_mode_trans_xy)
- && it->check_mode(it, inst_mode_trans_xy) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_trans_xy) == inst_ok) {
mode = inst_mode_trans_xy;
rmode = 2;
- } else if (IMODETST(cap, inst_mode_trans_strip)
- && it->check_mode(it, inst_mode_trans_strip) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_trans_strip) == inst_ok) {
mode = inst_mode_trans_strip;
rmode = 1;
} else {
@@ -482,23 +552,24 @@ a1log *log /* verb, debug & error log */
rmode = 0;
}
} else if (displ) {
+printf("~1 using displ mode\n");
/* We assume a display mode will always be spot by spot */
mode = inst_mode_emis_spot;
rmode = 0;
} else if (emis) {
- if (pbypatch && IMODETST(cap, inst_mode_emis_spot)
+printf("~1 using emis mode\n");
+ if (pbypatch
&& it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
mode = inst_mode_emis_spot;
rmode = 0;
- } else if (IMODETST(cap, inst_mode_emis_strip)
- && it->check_mode(it, inst_mode_emis_strip) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_emis_strip) == inst_ok) {
mode = inst_mode_emis_strip;
rmode = 1;
} else {
mode = inst_mode_emis_spot;
rmode = 0;
}
- } else {
+ } else { /* Reflectance */
inst_stat_savdrd sv = inst_stat_savdrd_none;
/* See if instrument has a saved mode, and if it has data that */
@@ -602,58 +673,50 @@ a1log *log /* verb, debug & error log */
}
if (pbypatch
- && IMODETST(cap, inst_mode_s_ref_spot)
&& it->check_mode(it, inst_mode_s_ref_spot) == inst_ok
&& (sv & inst_stat_savdrd_spot)) {
mode = inst_mode_s_ref_spot;
svdmode = 1;
rmode = 0;
- } else if (IMODETST(cap, inst_mode_s_ref_chart)
- && it->check_mode(it, inst_mode_s_ref_chart) == inst_ok
+ } else if (it->check_mode(it, inst_mode_s_ref_chart) == inst_ok
&& (sv & inst_stat_savdrd_chart)) {
mode = inst_mode_s_ref_chart;
svdmode = 1;
rmode = 3;
- } else if (IMODETST(cap, inst_mode_s_ref_xy)
- && it->check_mode(it, inst_mode_s_ref_xy) == inst_ok
+ } else if (it->check_mode(it, inst_mode_s_ref_xy) == inst_ok
&& (sv & inst_stat_savdrd_xy)) {
mode = inst_mode_s_ref_xy;
svdmode = 1;
rmode = 2;
- } else if (IMODETST(cap, inst_mode_s_ref_strip)
- && it->check_mode(it, inst_mode_s_ref_strip) == inst_ok
+ } else if (it->check_mode(it, inst_mode_s_ref_strip) == inst_ok
&& (sv & inst_stat_savdrd_strip)) {
mode = inst_mode_s_ref_strip;
svdmode = 1;
rmode = 1;
- } else if (IMODETST(cap, inst_mode_s_ref_spot)
- && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok
+ } else if (it->check_mode(it, inst_mode_s_ref_spot) == inst_ok
&& (sv & inst_stat_savdrd_spot)) {
mode = inst_mode_s_ref_spot;
svdmode = 1;
rmode = 0;
- } else if (pbypatch && IMODETST(cap, inst_mode_ref_spot)
+ } else if (pbypatch
&& it->check_mode(it, inst_mode_ref_spot) == inst_ok) {
mode = inst_mode_ref_spot;
rmode = 0;
- } else if (IMODETST(cap, inst_mode_ref_chart)
- && it->check_mode(it, inst_mode_ref_chart) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_ref_chart) == inst_ok) {
mode = inst_mode_ref_chart;
rmode = 3;
- } else if (IMODETST(cap, inst_mode_ref_xy)
- && it->check_mode(it, inst_mode_ref_xy) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_ref_xy) == inst_ok) {
mode = inst_mode_ref_xy;
rmode = 2;
- } else if (IMODETST(cap, inst_mode_ref_strip)
- && it->check_mode(it, inst_mode_ref_strip) == inst_ok) {
+ } else if (it->check_mode(it, inst_mode_ref_strip) == inst_ok) {
mode = inst_mode_ref_strip;
rmode = 1;
@@ -1076,6 +1139,12 @@ a1log *log /* verb, debug & error log */
int pai; /* Current pass in current strip */
int oroi; /* Overall row index */
+ if (
+ itype != instDTP20 &&
+ !rand && disbidi == 0) {
+ warning("Can't do bi-directional strip recognition without randomized patch locations");
+ }
+
/* Do any needed calibration before the user places the instrument on a desired spot */
if (it->needs_calibration(it) & inst_calt_n_dfrble_mask) {
if ((rv = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, 0))
@@ -1168,6 +1237,7 @@ a1log *log /* verb, debug & error log */
pai = 0;
}
//printf("~1 stix = %d, pis[stix] = %d, oroi = %d, rr %d\n",stix, pis[stix],oroi,scols[oroi * stipa]->rr);
+ // Note we aren't protecting agains a bodgy pis[] value
if (incflag == 1 || scols[oroi * stipa]->rr == 0 || oroi == s_oroi)
break;
}
@@ -1261,8 +1331,8 @@ a1log *log /* verb, debug & error log */
/* Not all rows have been read */
empty_con_chars();
- printf("\nDone ? - At least one unread patch (%s), Are you sure [y/n]: ",
- scols[i]->loc);
+ printf("\nDone ? - At least one unread patch (%s, %s), Are you sure [y/n]: ",
+ scols[i]->id, scols[i]->loc);
fflush(stdout);
ch = next_con_char();
printf("\n");
@@ -1333,7 +1403,8 @@ a1log *log /* verb, debug & error log */
return -1;
}
printf("\n");
- if (it->icom->port_type(it->icom) == icomt_serial) {
+ if ((it->icom->port_type(it->icom) & icomt_serial)
+ && !(it->icom->port_attr(it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = it->last_scomerr(it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -1386,9 +1457,9 @@ a1log *log /* verb, debug & error log */
double werror = 0.0; /* Worst case error in best correlation strip */
double xbcorr = 1e6; /* Expected pass correlation value */
- int xboff; /* Expected pass offset */
+ int xboff; /* Expected pass best offset */
int xbdir; /* Expected pass overall pass direction */
- double xwerror = 0.0; /* Expected pass worst error in best strip */
+ double xwerror = 0.0; /* Expected pass worst patcch error */
if (rand && disbidi == 0 && (cap2 & inst2_bidi_scan))
dirrg = 2; /* Enable bi-directional strip recognition */
@@ -1426,17 +1497,29 @@ a1log *log /* verb, debug & error log */
}
/* Compare just sample patches (not padding Max/Min) */
- for (pwerr = corr = 0.0, n = 0, i = 0; i < stipa; i++, n++) {
+#ifdef USESTRDELTA
+ for (pwerr = corr = 0.0, n = 0, i = 0; i < (stipa-1); i++, n++)
+#else
+ for (pwerr = corr = 0.0, n = 0, i = 0; i < stipa; i++, n++)
+#endif
+ {
double vcorr;
- int ix = i+skipp+toff;
- if (dir != 0)
+ int ix = i+skipp+toff, ix1 = ix+1;
+ if (dir != 0) {
ix = stipa - 1 - ix;
+ ix1 = stipa - 1 - ix1;
+ }
if (vals[ix].XYZ_v == 0)
error("Instrument didn't return XYZ value");
+#ifdef USESTRDELTA
+ vcorr = xyzLabcorr(vals[ix].XYZ, scb[i]->eXYZ,
+ vals[ix1].XYZ, scb[i+1]->eXYZ);
+#else
vcorr = xyzLabDE(ynorm, vals[ix].XYZ, scb[i]->eXYZ);
+#endif
//printf("DE %f from vals[%d] %f %f %f and scols[%d] %f %f %f\n", vcorr, ix, vals[ix].XYZ[0], vals[ix].XYZ[1], vals[ix].XYZ[2], i + choroi * stipa, scb[i]->eXYZ[0], scb[i]->eXYZ[1], scb[i]->eXYZ[2]);
corr += vcorr;
- if (vcorr > pwerr)
+ if (vcorr > pwerr) /* Worsed patch error */
pwerr = vcorr;
}
corr /= (double)n;
@@ -1444,16 +1527,16 @@ a1log *log /* verb, debug & error log */
printf(" Strip %d dir %d offset %d correlation = %f\n",choroi,dir,toff,corr);
#endif
- /* Expected strip correlation and */
- /* best fir to off by 1 and direction */
+ /* If this is the expected strip, */
+ /* note correlation and best fit to off by 1 and direction */
if (choroi == oroi && corr < xbcorr) {
- xbcorr = corr;
+ xbcorr = corr; /* Expected strip correlation */
xboff = toff;
xbdir = dir;
xwerror = pwerr; /* Expected passes worst error */
}
- /* Best matched strip correlation */
+ /* Best overall matched strip correlation */
if (corr < bcorr) {
boroi = choroi;
bcorr = corr;
@@ -1624,6 +1707,7 @@ a1log *log /* verb, debug & error log */
inst_set_uih('G', 'G', DUIH_CMND);
inst_set_uih('d', 'd', DUIH_CMND);
inst_set_uih('D', 'D', DUIH_CMND);
+ inst_set_uih('k', 'k', DUIH_CMND);
inst_set_uih('q', 'q', DUIH_ABORT);
inst_set_uih('Q', 'Q', DUIH_ABORT);
inst_set_uih(0xd, 0xd, DUIH_TRIG); /* Return */
@@ -1637,7 +1721,7 @@ a1log *log /* verb, debug & error log */
incflag = 3;
/* Until we're done */
- for(;pix < npat;) {
+ for (;pix < npat;) {
char buf[200], *bp = NULL, *ep = NULL;
char ch = 0;
@@ -1716,7 +1800,7 @@ a1log *log /* verb, debug & error log */
}
if (xtern != 0) { /* User entered values */
- printf("\nReady to read patch '%s'%s\n",scols[pix]->loc,
+ printf("\nReady to read patch '%s' at '%s'%s\n",scols[pix]->id, scols[pix]->loc,
i >= npat ? "(All patches read!)" :
strcmp(scols[pix]->id, "0") == 0 ? " (Padding Patch)" :
scols[pix]->rr ? " (Already read)" : "");
@@ -1747,7 +1831,7 @@ a1log *log /* verb, debug & error log */
empty_con_chars();
- printf("\nReady to read patch '%s'%s\n",scols[pix]->loc,
+ printf("\nReady to read patch '%s' at '%s'%s\n",scols[pix]->id, scols[pix]->loc,
i >= npat ? " (All patches read!)" :
strcmp(scols[pix]->id, "0") == 0 ? " (Padding Patch)" :
scols[pix]->rr ? " (Already read)" : "");
@@ -1755,7 +1839,7 @@ a1log *log /* verb, debug & error log */
printf("hit 'f' to move forward, 'F' move forward 10,\n");
printf(" 'b' to move back, 'B; to move back 10,\n");
printf(" 'n' for next unread, 'g' to goto patch,\n");
- printf(" 'd' when done, <esc> to abort,\n");
+ printf(" 'd' when done, 'k' to calibrate, <esc> to abort,\n");
if (uswitch)
printf(" Instrument switch, <return> or <space> to read:");
@@ -1772,7 +1856,7 @@ a1log *log /* verb, debug & error log */
good_beep();
ch = '0';
- /* Deal with user trigger */
+ /* Deal with user trigger via user interface callback function */
} else if ((rv & inst_mask) == inst_user_trig) {
if (cap2 & inst2_no_feedback)
good_beep();
@@ -1841,7 +1925,8 @@ a1log *log /* verb, debug & error log */
return -1;
}
printf("\n");
- if (it->icom->port_type(it->icom) == icomt_serial) {
+ if ((it->icom->port_type(it->icom) & icomt_serial)
+ && !(it->icom->port_attr(it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = it->last_scomerr(it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -1891,6 +1976,15 @@ a1log *log /* verb, debug & error log */
}
printf("\n");
continue;
+ } else if (ch == 'k') {
+ inst_code ev;
+
+ ev = inst_handle_calibrate(it, inst_calt_available, inst_calc_none, NULL, NULL, 0);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ it->del(it);
+ return -1;
+ }
+ continue;
} else if (ch == 'f') {
incflag = 1;
continue;
@@ -1920,8 +2014,8 @@ a1log *log /* verb, debug & error log */
/* Not all patches have been read */
empty_con_chars();
- printf("\nDone ? - At least one unread patch (%s), Are you sure [y/n]: ",
- scols[i]->loc);
+ printf("\nDone ? - At least one unread patch (%s, %s), Are you sure [y/n]: ",
+ scols[i]->id, scols[i]->loc);
fflush(stdout);
if ((ch = next_con_char()) == 0x1b) {
printf("\n");
@@ -1996,6 +2090,10 @@ a1log *log /* verb, debug & error log */
}
scols[pix]->rr = 1; /* Has been read */
printf(" Patch read OK\n");
+
+ if (doplot && val.sp.spec_n > 0)
+ xspect_plot_w(&val.sp, NULL, NULL, 0);
+
/* Advance to next patch. */
incflag = 1;
} else { /* Unrecognised response */
@@ -2018,7 +2116,7 @@ usage() {
fprintf(stderr,"usage: chartread [-options] outfile\n");
fprintf(stderr," -v Verbose mode\n");
fprintf(stderr," -c listno Set communication port from the following list (default %d)\n",COMPORT);
- if ((icmps = new_icompaths(NULL)) != NULL) {
+ if ((icmps = new_icompaths(g_log)) != NULL) {
icompath **paths;
if ((paths = icmps->paths) != NULL) {
int i;
@@ -2046,6 +2144,7 @@ usage() {
fprintf(stderr," p Polarising filter\n");
fprintf(stderr," 6 D65\n");
fprintf(stderr," u U.V. Cut\n");
+ fprintf(stderr," -A N|A|X|G XRGA conversion (default N)\n");
fprintf(stderr," -N Disable initial calibration of instrument if possible\n");
fprintf(stderr," -B Disable auto bi-directional strip recognition\n");
fprintf(stderr," -H Use high resolution spectrum mode (if available)\n");
@@ -2055,12 +2154,19 @@ usage() {
int i;
fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n");
fprintf(stderr," -Q observ Choose CIE Observer for CCSS instrument:\n");
+#ifdef SALONEINSTLIB
+ fprintf(stderr," 1931_2 (def), 1964_10\n");
+#else /* !SALONEINSTLIB */
fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
+#endif /* !SALONEINSTLIB */
}
fprintf(stderr," -T ratio Modify strip patch consistency tolerance by ratio\n");
fprintf(stderr," -S Suppress wrong strip & unexpected value warnings\n");
// fprintf(stderr," -Y U Test i1pro2 UV measurement mode\n");
fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
+#ifndef SALONEINSTLIB
+ fprintf(stderr," -P Plot spectral if patch by patch\n");
+#endif
fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
fprintf(stderr," outfile Base name for input[ti2]/output[ti3] file\n");
if (icmps != NULL)
@@ -2092,11 +2198,14 @@ int main(int argc, char *argv[]) {
int xtern = 0; /* Take external values, 1 = Lab, 2 = XYZ */
int spectral = 1; /* Save spectral information */
int uvmode = 0; /* ~~~ i1pro2 test mode ~~~ */
+ xcalstd scalstd = xcalstd_none; /* X-Rite calibration standard to set */
+ xcalstd ucalstd = xcalstd_none; /* X-Rite calibration standard actually used */
int accurate_expd = 0; /* Expected value assumed to be accurate */
int emit_warnings = 1; /* Emit warnings for wrong strip, unexpected value */
int dolab = 0; /* 1 = Save CIE as Lab, 2 = Save CIE as XYZ and Lab */
int doresume = 0; /* Resume reading a chart */
int nocal = 0; /* Disable initial calibration */
+ int doplot = 0; /* Plot spectral of patch by patch */
char ccxxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction/Colorimeter Calibration name */
icxObserverType obType = icxOT_default; /* ccss observer */
static char inname[MAXNAMEL+1] = { 0 }; /* Input cgats file base name */
@@ -2191,12 +2300,14 @@ int main(int argc, char *argv[]) {
obType = icxOT_CIE_1931_2;
} else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
obType = icxOT_CIE_1964_10;
+#ifndef SALONEINSTLIB
} else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
obType = icxOT_Stiles_Burch_2;
} else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
obType = icxOT_Judd_Voss_2;
} else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
obType = icxOT_Shaw_Fairchild_2;
+#endif /* !SALONEINSTLIB */
} else
usage();
}
@@ -2217,7 +2328,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage();
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -2320,6 +2431,27 @@ int main(int argc, char *argv[]) {
else
usage();
+ /* XRGA conversion */
+ } else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (na[0] == 'N')
+ scalstd = xcalstd_none;
+ else if (na[0] == 'A')
+ scalstd = xcalstd_xrga;
+ else if (na[0] == 'X')
+ scalstd = xcalstd_xrdi;
+ else if (na[0] == 'G')
+ scalstd = xcalstd_gmdi;
+ else
+ usage();
+
+#ifndef SALONEINSTLIB
+ /* Plot spectral patch by patch */
+ } else if (argv[fa][1] == 'P') {
+ doplot = 1;
+#endif
+
/* Extra flags */
} else if (argv[fa][1] == 'Y') {
if (na == NULL)
@@ -2392,7 +2524,7 @@ int main(int argc, char *argv[]) {
if ((itype = inst_enum(icg->t[0].kdata[ti])) == instUnknown)
error ("Unrecognised chart target instrument '%s'", icg->t[0].kdata[ti]);
} else {
- itype = instDTP41; /* Default chart target instrument */
+ itype = instI1Pro; /* Default chart target instrument */
}
}
@@ -2508,10 +2640,6 @@ int main(int argc, char *argv[]) {
tlen = atof(icg->t[0].kdata[ti]);
}
- if (itype != instDTP20 && !rand && disbidi == 0) {
- warning("Can't do bi-directional strip recognition without randomize patch locations");
- }
-
if (verb) {
printf("Steps in each Pass = %d\n",stipa);
printf("Passes in each Strip = ");
@@ -2537,6 +2665,8 @@ int main(int argc, char *argv[]) {
totpa = (npat + stipa -1)/stipa; /* Total passes for all strips */
runpat = stipa * totpa; /* Rounded up totao number of patches */
+ if (runpat < npat) /* (If pattern doesn't match patches) */
+ runpat = npat;
if ((cols = (chcol *)malloc(sizeof(chcol) * runpat)) == NULL)
error("Malloc failed!");
if ((scols = (chcol **)calloc(sizeof(chcol *), runpat)) == NULL)
@@ -2684,29 +2814,40 @@ int main(int argc, char *argv[]) {
cal = NULL;
}
- /* Set up the location sorted array of pointers */
- for (i = 0; i < npat; i++) {
- scols[i] = &cols[i];
- if ((cols[i].loci = patch_location_order(paix, saix, ixord, cols[i].loc)) < 0)
- error ("Bad location field value '%s' on patch %d", cols[i].loc, i);
- }
- for (; i < runpat; i++) { /* Extra on end */
- scols[i] = &cols[i];
- cols[i].loci = (totpa-1) * (256 - stipa) + i;
+ /* Set up the location sorted array of pointers. */
+ /* If the order is not randomized, we don't care what form */
+ /* the location identifiers take - i.e. they can be arbitrary. */
+ {
+ int badloc = 0;
+
+ for (i = 0; i < npat; i++) {
+ scols[i] = &cols[i];
+ if ((cols[i].loci = patch_location_order(paix, saix, ixord, cols[i].loc)) < 0)
+ badloc = 1;
+ }
+ for (; i < runpat; i++) { /* Extra on end */
+ scols[i] = &cols[i];
+ cols[i].loci = (totpa-1) * (256 - stipa) + i;
/* printf("~~extra = %d, %d\n",cols[i].loci >> 8, cols[i].loci & 255); */
- }
+ }
- /* Reset 'read' flag and all data */
- for (i = 0; i < runpat; i++) {
- cols[i].rr = 0;
- cols[i].XYZ[0] = -1.0;
- cols[i].XYZ[1] = -1.0;
- cols[i].XYZ[2] = -1.0;
- cols[i].sp.spec_n = 0;
- }
+ /* Reset 'read' flag and all data */
+ for (i = 0; i < runpat; i++) {
+ cols[i].rr = 0;
+ cols[i].XYZ[0] = -1.0;
+ cols[i].XYZ[1] = -1.0;
+ cols[i].XYZ[2] = -1.0;
+ cols[i].sp.spec_n = 0;
+ }
+
+ if (rand && badloc)
+ error ("Bad location field value '%s' on patch %d", cols[i].loc, i);
+ if (!badloc) {
#define HEAP_COMPARE(A,B) (A->loci < B->loci)
- HEAPSORT(chcol *, scols, npat);
+ HEAPSORT(chcol *, scols, npat);
+ }
+ }
/* If we're resuming a chartread, fill in all the patches that */
/* have been read. */
@@ -2840,17 +2981,20 @@ int main(int argc, char *argv[]) {
}
}
- if ((icmps = new_icompaths(g_log)) == NULL)
- error("Finding instrument paths failed");
- if ((ipath = icmps->get_path(icmps, comport)) == NULL)
- error("No instrument at port %d",comport);
+ if (!xtern) {
+ if ((icmps = new_icompaths(g_log)) == NULL)
+ error("Finding instrument paths failed");
+ if ((ipath = icmps->get_path(icmps, comport)) == NULL)
+ error("No instrument at port %d",comport);
+ }
/* Read all of the strips in */
if (read_strips(itype, scols, &atype, npat, totpa, stipa, pis, paix,
saix, ixord, rstart, rand, hex, ipath, fc, plen, glen, tlen,
- trans, emis, displ, dtype, fe, nocal, disbidi, highres, ccxxname, obType,
+ trans, emis, displ, dtype, fe, scalstd, &ucalstd, nocal, disbidi, highres,
+ ccxxname, obType,
scan_tol, pbypatch, xtern, spectral, uvmode, accurate_expd,
- emit_warnings, g_log) == 0) {
+ emit_warnings, doplot, g_log) == 0) {
/* And save the result */
int nrpat; /* Number of read patches */
@@ -2861,6 +3005,10 @@ int main(int argc, char *argv[]) {
/* Note what instrument the chart was read with */
ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(atype) , NULL);
+ /* X-Rite calibration standard (If reflective mode) */
+ if (displ == 0 && trans == 0 && ucalstd != xcalstd_none)
+ ocg->add_kword(ocg, 0, "DEVCALSTD",xcalstd2str(ucalstd), NULL);
+
/* Count patches actually read */
for (nrpat = i = 0; i < npat; i++) {
if (cols[i].rr) {
diff --git a/spectro/colorhug.c b/spectro/colorhug.c
index 7397314..fefe766 100644
--- a/spectro/colorhug.c
+++ b/spectro/colorhug.c
@@ -1138,8 +1138,7 @@ int *cbid) {
* error if it hasn't been initialised.
*/
static inst_code
-colorhug_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+colorhug_get_set_opt(inst *pp, inst_opt_type m, ...) {
colorhug *p = (colorhug *)pp;
inst_code ev = inst_ok;
@@ -1184,7 +1183,17 @@ colorhug_get_set_opt(inst *pp, inst_opt_type m, ...)
return colorhug_set_LEDs(p, mask);
}
- return inst_unsupported;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/colorhug.h b/spectro/colorhug.h
index 90fff6f..8617705 100644
--- a/spectro/colorhug.h
+++ b/spectro/colorhug.h
@@ -20,6 +20,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update colorhug_interp_error() and colorhug_interp_code() in colorhug.c */
/* if anything of these #defines are added or subtracted */
@@ -94,6 +98,10 @@ struct _colorhug {
/* Constructor */
extern colorhug *new_colorhug(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
+
#define COLORHUG_H
#endif /* COLORHUG_H */
diff --git a/spectro/conv.c b/spectro/conv.c
index 94023db..284a30c 100644
--- a/spectro/conv.c
+++ b/spectro/conv.c
@@ -64,7 +64,7 @@
#include "conv.h"
#include "icoms.h"
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
//#include <stdbool.h>
#include <sys/sysctl.h>
#include <sys/param.h>
@@ -81,7 +81,7 @@
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
# include <objc/objc-auto.h>
#endif
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#undef DEBUG
@@ -131,6 +131,8 @@ int next_con_char(void) {
return c;
}
+#ifdef NEVER // Don't need this now.
+
/* Horrible hack to poll stdin when we're not interactive. */
/* This has the drawback that the char and returm must be */
/* written in one operation for the character to be recognised - */
@@ -143,9 +145,12 @@ static int th_read_char(void *pp) {
DWORD bread;
if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ *rp = 0; /* We've started */
return 0;
}
+ *rp = 0; /* We've started */
+
if (ReadFile(stdinh, buf, 1, &bread, NULL)
&& bread == 1
&& buf[0] != '\r' && buf[0] != '\n') {
@@ -154,32 +159,65 @@ static int th_read_char(void *pp) {
return 0;
}
+#endif /* NEVER */
/* If there is one, return the next character from the keyboard, else return 0 */
/* (If not_interactive, always returns 0) */
int poll_con_char(void) {
if (not_interactive) { /* Can't assume that it's the console */
+
+#ifdef NEVER // Use better approach below.
athread *getch_thread = NULL;
- char c = 0;
+ volatile char c = 0xff;
/* This is pretty horrible. The problem is that we can't use */
/* any of MSWin's async file read functions, because we */
/* have no way of ensuring that the STD_INPUT_HANDLE has been */
/* opened with FILE_FLAG_OVERLAPPED. Used a thread instead... */
- /* ReOpenFile() would fix this, but it's not available in WinXP, only Visa+ :-( */
- if ((getch_thread = new_athread(th_read_char, &c)) != NULL) {
+ /* ReOpenFile() would in theory fix this, but it's not available in WinXP, only Visa+, */
+ /* and aparently doesn't work on stdin anyway! :-( */
+ if ((getch_thread = new_athread(th_read_char, (char *)&c)) != NULL) {
HANDLE stdinh;
if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
return 0;
}
- Sleep(100); /* We just hope 1 msec is enough for the thread to start */
- CancelIo(stdinh);
+ /* Wait for the thread to start */
+ while (c == 0xff) {
+ Sleep(10); /* We just hope 1 msec is enough for the thread to start */
+ }
+ Sleep(10); /* Give it time to read */
+ CancelIo(stdinh); /* May not work since ReadFile() is on a different thread ? */
getch_thread->del(getch_thread);
return c;
}
+#else /* ! NEVER */
+ /* This approach is very flakey from the console, but seems */
+ /* to work reliably when operated progromatically. */
+ HANDLE stdinh;
+ char buf[10] = { 0 }, c;
+ DWORD bread;
+
+ if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+// printf("Waiting\n");
+ if (WaitForSingleObject(stdinh, 1) == WAIT_OBJECT_0) {
+// printf("stdin signalled\n");
+
+// FlushFileBuffers(stdinh);
+// FlushConsoleInputBuffer(stdinh);
+ if (ReadFile(stdinh, buf, 1, &bread, NULL)) {
+ int i;
+// fprintf(stderr,"Read %d chars 0x%x 0x%x 0x%x\n",bread,buf[0],buf[1], buf[2]);
+ if (buf[0] != '\r' && buf[0] != '\n')
+ return buf[0];
+ return 0;
+ }
+ }
+#endif /* !NEVER */
return 0;
}
@@ -192,10 +230,23 @@ int poll_con_char(void) {
}
/* Suck all characters from the keyboard */
-/* (If not_interactive, does nothing) */
+/* (If not_interactive, does nothing ?) */
void empty_con_chars(void) {
if (not_interactive) {
+ HANDLE stdinh;
+ char buf[100] = { 0 }, c;
+ DWORD bread;
+
+ if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
+ return;
+ for (;;) {
+ if (WaitForSingleObject(stdinh, 1) == WAIT_OBJECT_0) {
+ ReadFile(stdinh, buf, 100, &bread, NULL);
+ } else {
+ break;
+ }
+ }
return;
}
@@ -211,51 +262,6 @@ void sleep(unsigned int secs) {
Sleep(secs * 1000);
}
-/* Sleep for the given number of msec */
-void msec_sleep(unsigned int msec) {
- Sleep(msec);
-}
-
-/* Return the current time in msec since */
-/* the first invokation of msec_time() */
-/* (Is this based on timeGetTime() ? ) */
-unsigned int msec_time() {
- unsigned int rv;
- static unsigned int startup = 0;
-
- rv = GetTickCount();
- if (startup == 0)
- startup = rv;
-
- return rv - startup;
-}
-
-/* Return the current time in usec */
-/* since the first invokation of usec_time() */
-/* Return -1.0 if not available */
-double usec_time() {
- double rv;
- LARGE_INTEGER val;
- static double scale = 0.0;
- static LARGE_INTEGER startup;
-
- if (scale == 0.0) {
- if (QueryPerformanceFrequency(&val) == 0)
- return -1.0;
- scale = 1000000.0/val.QuadPart;
- QueryPerformanceCounter(&val);
- startup.QuadPart = val.QuadPart;
-
- } else {
- QueryPerformanceCounter(&val);
- }
- val.QuadPart -= startup.QuadPart;
-
- rv = val.QuadPart * scale;
-
- return rv;
-}
-
static athread *beep_thread = NULL;
static int beep_delay;
static int beep_freq;
@@ -552,126 +558,6 @@ void empty_con_chars(void) {
tcflush(STDIN_FILENO, TCIFLUSH);
}
-/* Sleep for the given number of msec */
-/* (Note that OS X 10.9+ App Nap can wreck this, unless */
-/* it is turned off.) */
-void msec_sleep(unsigned int msec) {
-#ifdef NEVER
- if (msec > 1000) {
- unsigned int secs;
- secs = msec / 1000;
- msec = msec % 1000;
- sleep(secs);
- }
- usleep(msec * 1000);
-#else
- struct timespec ts;
-
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- nanosleep(&ts, NULL);
-#endif
-}
-
-
-#if defined(__APPLE__) && !defined(CLOCK_MONOTONIC)
-
-#include <mach/mach_time.h>
-
-unsigned int msec_time() {
- mach_timebase_info_data_t timebase;
- static uint64_t startup = 0;
- uint64_t time;
- double msec;
-
- time = mach_absolute_time();
- if (startup == 0)
- startup = time;
-
- mach_timebase_info(&timebase);
- time -= startup;
- msec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e6);
-
- return (unsigned int)floor(msec + 0.5);
-}
-
-/* Return the current time in usec */
-/* since the first invokation of usec_time() */
-double usec_time() {
- mach_timebase_info_data_t timebase;
- static uint64_t startup = 0;
- uint64_t time;
- double usec;
-
- time = mach_absolute_time();
- if (startup == 0)
- startup = time;
-
- mach_timebase_info(&timebase);
- time -= startup;
- usec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e3);
-
- return usec;
-}
-
-#else
-
-/* Return the current time in msec */
-/* since the first invokation of msec_time() */
-unsigned int msec_time() {
- unsigned int rv;
- static struct timespec startup = { 0, 0 };
- struct timespec cv;
-
- clock_gettime(CLOCK_MONOTONIC, &cv);
-
- /* Set time to 0 on first invocation */
- if (startup.tv_sec == 0 && startup.tv_nsec == 0)
- startup = cv;
-
- /* Subtract, taking care of carry */
- cv.tv_sec -= startup.tv_sec;
- if (startup.tv_nsec > cv.tv_nsec) {
- cv.tv_sec--;
- cv.tv_nsec += 1000000000;
- }
- cv.tv_nsec -= startup.tv_nsec;
-
- /* Convert nsec to msec */
- rv = cv.tv_sec * 1000 + cv.tv_nsec / 1000000;
-
- return rv;
-}
-
-/* Return the current time in usec */
-/* since the first invokation of usec_time() */
-double usec_time() {
- double rv;
- static struct timespec startup = { 0, 0 };
- struct timespec cv;
-
- clock_gettime(CLOCK_MONOTONIC, &cv);
-
- /* Set time to 0 on first invocation */
- if (startup.tv_sec == 0 && startup.tv_nsec == 0)
- startup = cv;
-
- /* Subtract, taking care of carry */
- cv.tv_sec -= startup.tv_sec;
- if (startup.tv_nsec > cv.tv_nsec) {
- cv.tv_sec--;
- cv.tv_nsec += 1000000000;
- }
- cv.tv_nsec -= startup.tv_nsec;
-
- /* Convert to usec */
- rv = cv.tv_sec * 1000000.0 + cv.tv_nsec/1000;
-
- return rv;
-}
-
-#endif
-
/* - - - - - - - - - - - - - - - - - - - - - - - - */
int acond_timedwait_imp(pthread_cond_t *cond, pthread_mutex_t *lock, int msec) {
@@ -699,7 +585,7 @@ int acond_timedwait_imp(pthread_cond_t *cond, pthread_mutex_t *lock, int msec) {
/* Set the current threads priority */
int set_interactive_priority() {
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#ifdef NEVER
int rv = 0;
struct task_category_policy tcatpolicy;
@@ -725,7 +611,7 @@ int set_interactive_priority() {
// a1logd(g_log, 8, "set_interactive_priority: set to important got %d\n",rv);
return rv;
#endif /* NEVER */
-#else /* !APPLE */
+#else /* !UNIX_APPLE */
int rv;
struct sched_param param;
param.sched_priority = 32;
@@ -734,11 +620,11 @@ int set_interactive_priority() {
rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
// a1logd(g_log, 8, "set_interactive_priority: set got %d\n",rv);
return rv;
-#endif /* !APPLE */
+#endif /* !UNIX_APPLE */
}
int set_normal_priority() {
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#ifdef NEVER
int rv = 0;
struct task_category_policy tcatpolicy;
@@ -763,7 +649,7 @@ int set_normal_priority() {
// a1logd(g_log, 8, "set_normal_priority: set to standard got %d\n",rv);
return rv;
#endif /* NEVER */
-#else /* !APPLE */
+#else /* !UNIX_APPLE */
struct sched_param param;
param.sched_priority = 0;
int rv;
@@ -771,7 +657,7 @@ int set_normal_priority() {
rv = pthread_setschedparam(pthread_self(), SCHED_OTHER, &param);
// a1logd(g_log, 8, "set_normal_priority: reset got %d\n",rv);
return rv;
-#endif /* !APPLE */
+#endif /* !UNIX_APPLE */
}
#endif /* NEVER */
@@ -786,7 +672,7 @@ static int beep_msec;
static int delayed_beep(void *pp) {
msec_sleep(beep_delay);
a1logd(g_log,8, "msec_beep activate\n");
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
AudioServicesPlayAlertSound(kUserPreferredAlert);
# else
@@ -812,7 +698,7 @@ void msec_beep(int delay, int freq, int msec) {
a1logw(g_log, "msec_beep: Delayed beep failed to create thread\n");
} else {
a1logd(g_log,8, "msec_beep activate\n");
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
AudioServicesPlayAlertSound(kUserPreferredAlert);
# else
@@ -980,7 +866,7 @@ int create_parent_directories(char *path) {
#endif /* defined(UNIX) */
/* - - - - - - - - - - - - - - - - - - - - - - - - */
-#if defined(__APPLE__) || defined(NT)
+#if defined(UNIX_APPLE) || defined(NT)
/* Thread to monitor and kill the named processes */
static int th_kkill_nprocess(void *pp) {
@@ -1109,7 +995,7 @@ int kill_nprocess(char **pname, a1log *log) {
#endif /* NT */
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
/* Kill a list of named process. */
/* Kill the first process found, then return */
@@ -1188,411 +1074,8 @@ int kill_nprocess(char **pname, a1log *log) {
return rv;
}
-#endif /* __APPLE__ */
-
-#endif /* __APPLE__ || NT */
-
-/* ============================================================= */
-
-/* A very small subset of icclib, copied to here. */
-/* This is just enough to support the standalone instruments */
-#ifdef SALONEINSTLIB
-
-sa_XYZNumber sa_D50 = {
- 0.9642, 1.0000, 0.8249
-};
-
-sa_XYZNumber sa_D65 = {
- 0.9505, 1.0000, 1.0890
-};
-
-void sa_SetUnity3x3(double mat[3][3]) {
- int i, j;
- for (j = 0; j < 3; j++) {
- for (i = 0; i < 3; i++) {
- if (i == j)
- mat[j][i] = 1.0;
- else
- mat[j][i] = 0.0;
- }
- }
-
-}
-
-void sa_Cpy3x3(double dst[3][3], double src[3][3]) {
- int i, j;
-
- for (j = 0; j < 3; j++) {
- for (i = 0; i < 3; i++)
- dst[j][i] = src[j][i];
- }
-}
-
-void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]) {
- double tt[3];
-
- tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
- tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
- tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
+#endif /* UNIX_APPLE */
- out[0] = tt[0];
- out[1] = tt[1];
- out[2] = tt[2];
-}
-
-void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]) {
- int i, j, k;
- double td[3][3]; /* Temporary dest */
-
- for (j = 0; j < 3; j++) {
- for (i = 0; i < 3; i++) {
- double tt = 0.0;
- for (k = 0; k < 3; k++)
- tt += src1[j][k] * src2[k][i];
- td[j][i] = tt;
- }
- }
-
- /* Copy result out */
- for (j = 0; j < 3; j++)
- for (i = 0; i < 3; i++)
- dst[j][i] = td[j][i];
-}
-
-
-/* Matrix Inversion by Richard Carling from "Graphics Gems", Academic Press, 1990 */
-#define det2x2(a, b, c, d) (a * d - b * c)
-
-static void adjoint(
-double out[3][3],
-double in[3][3]
-) {
- double a1, a2, a3, b1, b2, b3, c1, c2, c3;
-
- /* assign to individual variable names to aid */
- /* selecting correct values */
-
- a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
- a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
- a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
-
- /* row column labeling reversed since we transpose rows & columns */
-
- out[0][0] = det2x2(b2, b3, c2, c3);
- out[1][0] = - det2x2(a2, a3, c2, c3);
- out[2][0] = det2x2(a2, a3, b2, b3);
-
- out[0][1] = - det2x2(b1, b3, c1, c3);
- out[1][1] = det2x2(a1, a3, c1, c3);
- out[2][1] = - det2x2(a1, a3, b1, b3);
-
- out[0][2] = det2x2(b1, b2, c1, c2);
- out[1][2] = - det2x2(a1, a2, c1, c2);
- out[2][2] = det2x2(a1, a2, b1, b2);
-}
-
-static double sa_Det3x3(double in[3][3]) {
- double a1, a2, a3, b1, b2, b3, c1, c2, c3;
- double ans;
-
- a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
- a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
- a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
-
- ans = a1 * det2x2(b2, b3, c2, c3)
- - b1 * det2x2(a2, a3, c2, c3)
- + c1 * det2x2(a2, a3, b2, b3);
- return ans;
-}
-
-#define SA__SMALL_NUMBER 1.e-8
-
-int sa_Inverse3x3(double out[3][3], double in[3][3]) {
- int i, j;
- double det;
-
- /* calculate the 3x3 determinant
- * if the determinant is zero,
- * then the inverse matrix is not unique.
- */
- det = sa_Det3x3(in);
-
- if ( fabs(det) < SA__SMALL_NUMBER)
- return 1;
-
- /* calculate the adjoint matrix */
- adjoint(out, in);
-
- /* scale the adjoint matrix to get the inverse */
- for (i = 0; i < 3; i++)
- for(j = 0; j < 3; j++)
- out[i][j] /= det;
- return 0;
-}
-
-#undef SA__SMALL_NUMBER
-#undef det2x2
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - */
-/* Transpose a 3x3 matrix */
-void sa_Transpose3x3(double out[3][3], double in[3][3]) {
- int i, j;
- if (out != in) {
- for (i = 0; i < 3; i++)
- for (j = 0; j < 3; j++)
- out[i][j] = in[j][i];
- } else {
- double tt[3][3];
- for (i = 0; i < 3; i++)
- for (j = 0; j < 3; j++)
- tt[i][j] = in[j][i];
- for (i = 0; i < 3; i++)
- for (j = 0; j < 3; j++)
- out[i][j] = tt[i][j];
- }
-}
-
-/* Scale a 3 vector by the given ratio */
-void sa_Scale3(double out[3], double in[3], double rat) {
- out[0] = in[0] * rat;
- out[1] = in[1] * rat;
- out[2] = in[2] * rat;
-}
-
-/* Clamp a 3 vector to be +ve */
-void sa_Clamp3(double out[3], double in[3]) {
- int i;
- for (i = 0; i < 3; i++)
- out[i] = in[i] < 0.0 ? 0.0 : in[i];
-}
-
-/* Return the normal Delta E given two Lab values */
-double sa_LabDE(double *Lab0, double *Lab1) {
- double rv = 0.0, tt;
-
- tt = Lab0[0] - Lab1[0];
- rv += tt * tt;
- tt = Lab0[1] - Lab1[1];
- rv += tt * tt;
- tt = Lab0[2] - Lab1[2];
- rv += tt * tt;
-
- return sqrt(rv);
-}
-
-/* CIE XYZ to perceptual CIE 1976 L*a*b* */
-void
-sa_XYZ2Lab(icmXYZNumber *w, double *out, double *in) {
- double X = in[0], Y = in[1], Z = in[2];
- double x,y,z,fx,fy,fz;
-
- x = X/w->X;
- y = Y/w->Y;
- z = Z/w->Z;
-
- if (x > 0.008856451586)
- fx = pow(x,1.0/3.0);
- else
- fx = 7.787036979 * x + 16.0/116.0;
-
- if (y > 0.008856451586)
- fy = pow(y,1.0/3.0);
- else
- fy = 7.787036979 * y + 16.0/116.0;
-
- if (z > 0.008856451586)
- fz = pow(z,1.0/3.0);
- else
- fz = 7.787036979 * z + 16.0/116.0;
-
- out[0] = 116.0 * fy - 16.0;
- out[1] = 500.0 * (fx - fy);
- out[2] = 200.0 * (fy - fz);
-}
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - */
-/* A sub-set of ludecomp code from numlib */
-
-int sa_lu_decomp(double **a, int n, int *pivx, double *rip) {
- int i, j;
- double *rscale, RSCALE[10];
-
- if (n <= 10)
- rscale = RSCALE;
- else
- rscale = dvector(0, n-1);
-
- for (i = 0; i < n; i++) {
- double big;
- for (big = 0.0, j=0; j < n; j++) {
- double temp;
- temp = fabs(a[i][j]);
- if (temp > big)
- big = temp;
- }
- if (fabs(big) <= DBL_MIN) {
- if (rscale != RSCALE)
- free_dvector(rscale, 0, n-1);
- return 1;
- }
- rscale[i] = 1.0/big;
- }
-
- for (*rip = 1.0, j = 0; j < n; j++) {
- double big;
- int k, bigi = 0;
-
- for (i = 0; i < j; i++) {
- double sum;
- sum = a[i][j];
- for (k = 0; k < i; k++)
- sum -= a[i][k] * a[k][j];
- a[i][j] = sum;
- }
-
- for (big = 0.0, i = j; i < n; i++) {
- double sum, temp;
- sum = a[i][j];
- for (k = 0; k < j; k++)
- sum -= a[i][k] * a[k][j];
- a[i][j] = sum;
- temp = rscale[i] * fabs(sum);
- if (temp >= big) {
- big = temp;
- bigi = i;
- }
- }
-
- if (j != bigi) {
- {
- double *temp;
- temp = a[bigi];
- a[bigi] = a[j];
- a[j] = temp;
- }
- *rip = -(*rip);
- rscale[bigi] = rscale[j];
- }
-
- pivx[j] = bigi;
- if (fabs(a[j][j]) <= DBL_MIN) {
- if (rscale != RSCALE)
- free_dvector(rscale, 0, n-1);
- return 1;
- }
-
- if (j != (n-1)) {
- double temp;
- temp = 1.0/a[j][j];
- for (i = j+1; i < n; i++)
- a[i][j] *= temp;
- }
- }
- if (rscale != RSCALE)
- free_dvector(rscale, 0, n-1);
- return 0;
-}
-
-void sa_lu_backsub(double **a, int n, int *pivx, double *b) {
- int i, j;
- int nvi;
-
- for (nvi = -1, i = 0; i < n; i++) {
- int px;
- double sum;
-
- px = pivx[i];
- sum = b[px];
- b[px] = b[i];
- if (nvi >= 0) {
- for (j = nvi; j < i; j++)
- sum -= a[i][j] * b[j];
- } else {
- if (sum != 0.0)
- nvi = i;
- }
- b[i] = sum;
- }
-
- for (i = (n-1); i >= 0; i--) {
- double sum;
- sum = b[i];
- for (j = i+1; j < n; j++)
- sum -= a[i][j] * b[j];
- b[i] = sum/a[i][i];
- }
-}
-
-int sa_lu_invert(double **a, int n) {
- int i, j;
- double rip;
- int *pivx, PIVX[10];
- double **y;
-
- if (n <= 10)
- pivx = PIVX;
- else
- pivx = ivector(0, n-1);
-
- if (sa_lu_decomp(a, n, pivx, &rip)) {
- if (pivx != PIVX)
- free_ivector(pivx, 0, n-1);
- return 1;
- }
-
- y = dmatrix(0, n-1, 0, n-1);
- for (i = 0; i < n; i++) {
- for (j = 0; j < n; j++) {
- y[i][j] = a[i][j];
- }
- }
-
- for (i = 0; i < n; i++) {
- for (j = 0; j < n; j++)
- a[i][j] = 0.0;
- a[i][i] = 1.0;
- sa_lu_backsub(y, n, pivx, a[i]);
- }
-
- free_dmatrix(y, 0, n-1, 0, n-1);
- if (pivx != PIVX)
- free_ivector(pivx, 0, n-1);
-
- return 0;
-}
-
-int sa_lu_psinvert(double **out, double **in, int m, int n) {
- int rv = 0;
- double **tr;
- double **sq;
-
- tr = dmatrix(0, n-1, 0, m-1);
- matrix_trans(tr, in, m, n);
-
- if (m > n) {
- sq = dmatrix(0, n-1, 0, n-1);
- if ((rv = matrix_mult(sq, n, n, tr, n, m, in, m, n)) == 0) {
- if ((rv = sa_lu_invert(sq, n)) == 0) {
- rv = matrix_mult(out, n, m, sq, n, n, tr, n, m);
- }
- }
- free_dmatrix(sq, 0, n-1, 0, n-1);
- } else {
- sq = dmatrix(0, m-1, 0, m-1);
- if ((rv = matrix_mult(sq, m, m, in, m, n, tr, n, m)) == 0) {
- if ((rv = sa_lu_invert(sq, m)) == 0) {
- rv = matrix_mult(out, n, m, tr, n, m, sq, m, m);
- }
- }
- free_dmatrix(sq, 0, m-1, 0, m-1);
- }
-
- free_dmatrix(tr, 0, n-1, 0, m-1);
- return rv;
-}
-
-
-#endif /* SALONEINSTLIB */
-/* ============================================================= */
+#endif /* UNIX_APPLE || NT */
diff --git a/spectro/conv.h b/spectro/conv.h
index 4e14dd9..a6adcbf 100644
--- a/spectro/conv.h
+++ b/spectro/conv.h
@@ -32,7 +32,7 @@
# include <io.h>
#endif
-#if defined (UNIX) || defined(__APPLE__)
+#if defined(UNIX)
# include <unistd.h>
# include <glob.h>
# include <pthread.h>
@@ -57,19 +57,8 @@ int poll_con_char(void);
/* (If not_interactive, does nothing) */
void empty_con_chars(void);
-/* Sleep for the given number of msec */
-void msec_sleep(unsigned int msec);
-
-/* Return the current time in msec since */
-/* the first invokation of msec_time() */
-unsigned int msec_time();
-
-/* Return the current time in usec */
-/* the first invokation of usec_time() */
-double usec_time();
-
/* Activate the system beeper after a delay */
-/* (Note frequancy and duration may not be honoured on all systems) */
+/* (Note frequency and duration may not be honoured on all systems) */
void msec_beep(int delay, int freq, int msec);
void normal_beep(); /* Emit a "normal" beep */
@@ -149,7 +138,7 @@ struct _athread {
#if defined (NT)
HANDLE th; /* Thread */
#endif
-#if defined (UNIX) || defined(__APPLE__)
+#if defined(UNIX)
pthread_t thid; /* Thread ID */
#endif
int finished; /* Set when the thread returned */
@@ -197,7 +186,7 @@ struct _kkill_nproc_ctx {
void (*del)(struct _kkill_nproc_ctx *p);
}; typedef struct _kkill_nproc_ctx kkill_nproc_ctx;
-#if defined(__APPLE__) || defined(NT)
+#if defined(UNIX_APPLE) || defined(NT)
/* Kill a list of named processes. NULL for last */
/* return < 0 if this fails. */
@@ -209,65 +198,10 @@ int kill_nprocess(char **pname, a1log *log);
/* Call ctx->del() when done */
kkill_nproc_ctx *kkill_nprocess(char **pname, a1log *log);
-#endif /* __APPLE__ || NT */
+#endif /* UNIX_APPLE || NT */
#include "xdg_bds.h"
-/* - - - - - - - - - - - - - - - - - - -- */
-/* A very small subset of icclib */
-#ifdef SALONEINSTLIB
-
-typedef struct {
- double X;
- double Y;
- double Z;
-} sa_XYZNumber;
-
-typedef enum {
- sa_SigXYZData = 0x58595A20L, /* 'XYZ ' */
- sa_SigLabData = 0x4C616220L /* 'Lab ' */
-} sa_ColorSpaceSignature;
-
-extern sa_XYZNumber sa_D50;
-extern sa_XYZNumber sa_D65;
-void sa_SetUnity3x3(double mat[3][3]);
-void sa_Cpy3x3(double out[3][3], double mat[3][3]);
-void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]);
-void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]);
-int sa_Inverse3x3(double out[3][3], double in[3][3]);
-void sa_Transpose3x3(double out[3][3], double in[3][3]);
-void sa_Scale3(double out[3], double in[3], double rat);
-double sa_LabDE(double *in0, double *in1);
-
-
-#define icmXYZNumber sa_XYZNumber
-#define icColorSpaceSignature sa_ColorSpaceSignature
-#define icSigXYZData sa_SigXYZData
-#define icSigLabData sa_SigLabData
-#define icmD50 sa_D50
-#define icmD65 sa_D65
-#define icmSetUnity3x3 sa_SetUnity3x3
-#define icmCpy3x3 sa_Cpy3x3
-#define icmMulBy3x3 sa_MulBy3x3
-#define icmMul3x3_2 sa_Mul3x3_2
-#define icmInverse3x3 sa_Inverse3x3
-#define icmTranspose3x3 sa_Transpose3x3
-#define icmScale3 sa_Scale3
-#define icmClamp3 sa_Clamp3
-#define icmLabDE sa_LabDE
-#define icmXYZ2Lab sa_XYZ2Lab
-
-/* A subset of numlib */
-
-int sa_lu_psinvert(double **out, double **in, int m, int n);
-
-#define lu_psinvert sa_lu_psinvert
-
-#endif /* SALONEINSTLIB */
-
-/* - - - - - - - - - - - - - - - - - - -- */
-
-
#ifdef __cplusplus
}
#endif
diff --git a/spectro/cubecal.h b/spectro/cubecal.h
index 60f7380..93f1ada 100644
--- a/spectro/cubecal.h
+++ b/spectro/cubecal.h
@@ -1,6 +1,7 @@
/*
* Calibration Table for SwatchMate Cube
+ * This is #included in smcube.c
*
* Copyright 2015 Graeme W. Gill
* All rights reserved
diff --git a/spectro/dev.h b/spectro/dev.h
new file mode 100644
index 0000000..0b62de3
--- /dev/null
+++ b/spectro/dev.h
@@ -0,0 +1,41 @@
+
+#ifndef DEV_H
+
+/*
+ * Abstract base class for all devices handled here.
+ */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/8/2016
+ *
+ * Copyright 2016 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ */
+
+#include "icoms.h" /* libinst Includes this functionality */
+#include "conv.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Device base object. */
+#define DEV_OBJ_BASE \
+ a1log *log; /* Pointer to debug & error logging class */ \
+ icoms *icom; /* Device coms object */ \
+ instType itype; /* Device type determined by driver */ \
+
+/* The base object type */
+struct _dev {
+ DEV_OBJ_BASE
+ }; typedef struct _dev dev;
+
+#define DEV_H
+#endif /* DEV_H */
diff --git a/spectro/dispcal.c b/spectro/dispcal.c
index 97337cd..65e2f10 100644
--- a/spectro/dispcal.c
+++ b/spectro/dispcal.c
@@ -62,8 +62,13 @@
Change white point gamut clipping to be a measurement
search rather than computing from primary XYZ ?
- Add bell at end of calibration ?
+ Handling of white and black device clipping is not so good.
+ White clipping isn't characterized very well due to sparse sampling,
+ and moncurve tends to smooth over the clip inflection point,
+ making it innacurate. This particularly hurts the black point
+ accuracy, leading to raised or crushed blacks.
+ Add bell at end of calibration ?
Add option to plot graph of native and calibrated RGB ?
@@ -1012,7 +1017,7 @@ static void init_csamp(csamp *p, calx *x, int doupdate, int verify, int psrand,
p->_no = p->no = no;
- if ((p->s = (csp *)malloc(p->_no * sizeof(csp))) == NULL)
+ if ((p->s = (csp *)calloc(p->_no, sizeof(csp))) == NULL)
error("csamp malloc failed");
/* Compute v and txyz */
@@ -1715,7 +1720,7 @@ int main(int argc, char *argv[]) {
set_exe_path(argv[0]); /* Set global exe_path and error_program */
check_if_not_interactive();
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
{
SInt32 MacMajVers, MacMinVers, MacBFVers;
@@ -1939,7 +1944,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage(0,"Paramater expected following -W");
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -2572,7 +2577,7 @@ int main(int argc, char *argv[]) {
#ifdef MEAS_RES
if (doreport == 1) {
if (sigbits == 0) {
- warning("Unable to determine Video LUT entry bit depth");
+ warning("Unable to determine effective Video LUT entry bit depth");
} else {
printf("Effective Video LUT entry depth seems to be %d bits\n",sigbits);
}
@@ -3701,8 +3706,9 @@ int main(int argc, char *argv[]) {
else
printf(" Current Brightness = %.2f\n", tcols[2].XYZ[1]);
- printf(" Target 50%% Level = %.3f, Current = %.3f, error = % .1f%%\n",
+ printf(" Target 50%% Level = %.3f, Current = %.3f (Aprox. Gamma %.2f), error = % .1f%%\n",
tarh, tcols[1].XYZ[1],
+ mgamma,
100.0 * (tcols[1].XYZ[1] - tarh)/tarw);
printf(" Target Near Black = %.4f, Current = %.4f, error = % .1f%%\n",
@@ -4354,7 +4360,7 @@ int main(int argc, char *argv[]) {
0.2, /* Background relative to reference white */
80.0, /* Display is 80 cd/m^2 */
0.0, 0.01, x.nwh, /* 0% flare and 1% glare same white point */
- 0);
+ 0, 1.0);
break;
case gt_Rec709:
@@ -4365,7 +4371,7 @@ int main(int argc, char *argv[]) {
0.2, /* Background relative to reference white */
1000.0/3.1415, /* Luminance of white in the Image field (cd/m^2) */
0.0, 0.01, x.nwh, /* 0% flare and 1% glare same white point */
- 0);
+ 0, 1.0);
break;
default:
@@ -4378,7 +4384,7 @@ int main(int argc, char *argv[]) {
0.2, /* Background relative to reference white */
x.twh[1], /* Target white level (cd/m^2) */
0.0, 0.01, x.nwh, /* 0% flare and 1% glare same white point */
- 0);
+ 0, 1.0);
/* Compute the normalisation values */
x.svc->XYZ_to_cam(x.svc, Jab, x.nwh); /* Relative white point */
@@ -4532,7 +4538,10 @@ int main(int argc, char *argv[]) {
}
#endif
- dr->reset_targ_w(dr); /* Reset white drift target at start of main cal. */
+ /* If native white and white drift compensation enabled, */
+ /* reset white drift target at start of main cal. */
+ if (x.nat && asgrey.s[0].v == 1.0 && wdrift)
+ dr->reset_targ_w(dr);
/* Now we go into the main verify & refine loop */
for (it = (verify == 2) ? mxits : 0;
@@ -5485,6 +5494,29 @@ int main(int argc, char *argv[]) {
if ((wr_icco = new_icc()) == NULL)
error("Write: Creation of ICC object failed");
+ /* Set the header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigDisplayClass;
+ wh->colorSpace = icSigRgbData; /* Display is RGB */
+ wh->pcs = icSigXYZData; /* XYZ for matrix based profile */
+ wh->renderingIntent = icRelativeColorimetric; /* For want of something */
+
+ wh->manufacturer = icmSigUnknownType;
+ wh->model = icmSigUnknownType;
+#ifdef NT
+ wh->platform = icSigMicrosoft;
+#endif
+#ifdef UNIX_APPLE
+ wh->platform = icSigMacintosh;
+#endif
+#if defined(UNIX_X11)
+ wh->platform = icmSig_nix;
+#endif
+ }
+
/* Lookup white and black points */
{
int j;
@@ -5561,9 +5593,9 @@ int main(int argc, char *argv[]) {
printf("RGB 1 through matrix = XYZ %f %f %f, Lab %f %f %f\n", xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
}
#endif
- /* Adapt matrix */
+ /* Chromatic Adaptation matrix */
icmAry2XYZ(swp, wp);
- wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_MULMATRIX, icmD50, swp, mat);
+ wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_MULMATRIX, NULL, mat, icmD50, swp);
#ifdef NEVER
{
double rgb[3], xyz[3], lab[3];
@@ -5603,9 +5635,9 @@ int main(int argc, char *argv[]) {
printf("RGB cal through matrix = XYZ %f %f %f, Lab %f %f %f\n", xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
}
#endif
- /* Adapt matrix */
+ /* Chromatic Adaptation matrix */
icmAry2XYZ(swp, wp);
- wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_MULMATRIX, icmD50, swp, mat);
+ wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_MULMATRIX, NULL, mat, icmD50, swp);
#ifdef NEVER
{
double rgb[3], xyz[3], lab[3];
@@ -5619,30 +5651,7 @@ int main(int argc, char *argv[]) {
}
}
- /* Add all the tags required */
-
- /* The header: */
- {
- icmHeader *wh = wr_icco->header;
-
- /* Values that must be set before writing */
- wh->deviceClass = icSigDisplayClass;
- wh->colorSpace = icSigRgbData; /* Display is RGB */
- wh->pcs = icSigXYZData; /* XYZ for matrix based profile */
- wh->renderingIntent = icRelativeColorimetric; /* For want of something */
-
- wh->manufacturer = icmSigUnknownType;
- wh->model = icmSigUnknownType;
-#ifdef NT
- wh->platform = icSigMicrosoft;
-#endif
-#ifdef __APPLE__
- wh->platform = icSigMacintosh;
-#endif
-#if defined(UNIX_X11)
- wh->platform = icmSig_nix;
-#endif
- }
+ /* Add all the other tags required */
/* Profile Description Tag: */
{
@@ -5715,6 +5724,7 @@ int main(int argc, char *argv[]) {
wr_icco, icSigLuminanceTag, icSigXYZArrayType)) == NULL)
error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ /* (Only Y is used according to the ICC spec.) */
wo->size = 1;
wo->allocate((icmBase *)wo); /* Allocate space */
wo->data[0].X = 0.0;
diff --git a/spectro/dispread.c b/spectro/dispread.c
index 8a78fcc..4c96b76 100644
--- a/spectro/dispread.c
+++ b/spectro/dispread.c
@@ -271,7 +271,7 @@ int main(int argc, char *argv[]) {
/* 0X = use current color management cLut (MadVR) */
/* 1X = disable color management cLUT (MadVR) */
double cal[3][MAX_CAL_ENT]; /* Display calibration */
- int ncal = 256; /* number of cal entries used */
+ int ncal = 256; /* Default number of cal entries used */
cgats *icg; /* input cgats structure */
cgats *ocg; /* output cgats structure */
time_t clk = time(0);
@@ -572,7 +572,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage(0,"Parameter expected after -W");
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -855,8 +855,9 @@ int main(int argc, char *argv[]) {
if ((ncal = ccg->t[0].nsets) <= 0)
error ("No data in set of file '%s'",calname);
- if (ncal != 256)
- error ("Expect 256 data sets in file '%s'",calname);
+ if (ncal < 2 || ncal > MAX_CAL_ENT)
+ error("Data set size %d is out of range for '%s'",ncal,calname);
+
if (ncal > MAX_CAL_ENT)
error ("Cant handle %d data sets in file '%s', max is %d",ncal,calname,MAX_CAL_ENT);
diff --git a/spectro/dispsup.c b/spectro/dispsup.c
index 57a598e..281912d 100644
--- a/spectro/dispsup.c
+++ b/spectro/dispsup.c
@@ -281,18 +281,28 @@ a1log *log /* Verb, debug & error log */
itype = p->get_itype(p); /* Actual type */
p->capabilities(p, &cap, &cap2, &cap3);
- if (tele && !IMODETST(cap, inst_mode_emis_tele)) {
+ if (tele && p->check_mode(p, inst_mode_emis_tele) != inst_ok) {
printf("Want telephoto measurement capability but instrument doesn't support it\n");
printf("so falling back to emissive spot mode.\n");
tele = 0;
}
- if (!tele && !IMODETST(cap, inst_mode_emis_spot)) {
+ if (!tele && p->check_mode(p, inst_mode_emis_spot) != inst_ok) {
printf("Want emissive spot measurement capability but instrument doesn't support it\n");
printf("so switching to telephoto spot mode.\n");
tele = 1;
}
+ if (( tele && p->check_mode(p, inst_mode_emis_tele) != inst_ok)
+ || (!tele && p->check_mode(p, inst_mode_emis_spot) != inst_ok)) {
+ printf("Need %s emissive measurement capability,\n", tele ? "telephoto" : "spot");
+ printf("but instrument doesn't support it\n");
+ a1logd(p->log,1,"Need %s emissive measurement capability but device doesn't support it,\n",
+ tele ? "telephoto" : "spot");
+ p->del(p);
+ return -1;
+ }
+
/* Set to emission mode to read a display */
if (tele)
mode = inst_mode_emis_tele;
@@ -434,6 +444,7 @@ static int disprd_read_imp(
ipatch val; /* Return value */
int ch; /* Character */
int cal_type;
+ inst_calc_id_type idtype;
char id[CALIDLEN];
inst2_capability cap2;
@@ -521,7 +532,7 @@ static int disprd_read_imp(
return 3;
}
/* Do calibrate, but ignore return code. Press on regardless. */
- if ((rv = p->it->calibrate(p->it, &calt, &calc, id)) != inst_ok) {
+ if ((rv = p->it->calibrate(p->it, &calt, &calc, &idtype, id)) != inst_ok) {
a1logd(p->log,1,"warning, frequency calibrate failed with '%s' (%s)\n",
p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
}
@@ -538,7 +549,7 @@ static int disprd_read_imp(
return 3;
}
/* Do calibrate, but ignore return code. Press on regardless. */
- if ((rv = p->it->calibrate(p->it, &calt, &calc, id)) != inst_ok) {
+ if ((rv = p->it->calibrate(p->it, &calt, &calc, &idtype, id)) != inst_ok) {
a1logd(p->log,1,"warning, display integration calibrate failed with '%s' (%s)\n",
p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
}
@@ -681,7 +692,8 @@ static int disprd_read_imp(
return 1;
}
printf("\n");
- if (p->it->icom->port_type(p->it->icom) == icomt_serial) {
+ if ((p->it->icom->port_type(p->it->icom) & icomt_serial)
+ && !(p->it->icom->port_attr(p->it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = p->it->last_scomerr(p->it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -1198,7 +1210,7 @@ int disprd_ambient(
p->it->capabilities(p->it, &cap, &cap2, &cap3);
}
- if (!IMODETST(cap, inst_mode_emis_ambient)) {
+ if (p->it->check_mode(p->it, inst_mode_emis_ambient) != inst_ok) {
printf("Need ambient measurement capability,\n");
printf("but instrument doesn't support it\n");
return 8;
@@ -1297,7 +1309,7 @@ int disprd_ambient(
setup_display_calibrate, &dwi, 0);
setup_display_calibrate(p->it,inst_calc_none, &dwi);
if (rv != inst_ok) { /* Abort or fatal error */
- return 1;
+ return ((rv & inst_mask) == inst_user_abort) ? 1 : 2;
}
continue;
@@ -1336,7 +1348,8 @@ int disprd_ambient(
return 1;
}
printf("\n");
- if (p->it->icom->port_type(p->it->icom) == icomt_serial) {
+ if ((p->it->icom->port_type(p->it->icom) & icomt_serial)
+ && !(p->it->icom->port_attr(p->it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = p->it->last_scomerr(p->it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -2146,21 +2159,21 @@ static int config_inst_displ(disprd *p) {
p->it->capabilities(p->it, &cap, &cap2, &cap3);
- if (p->tele && !IMODETST(cap, inst_mode_emis_tele)) {
+ if (p->tele && p->it->check_mode(p->it, inst_mode_emis_tele) != inst_ok) {
printf("Want telephoto measurement capability but instrument doesn't support it\n");
printf("so falling back to spot mode.\n");
a1logd(p->log,1,"No telephoto mode so falling back to spot mode.\n");
p->tele = 0;
}
- if (!p->tele && !IMODETST(cap, inst_mode_emis_spot)) {
+ if (!p->tele && p->it->check_mode(p->it, inst_mode_emis_spot) != inst_ok) {
printf("Want emissive spot measurement capability but instrument doesn't support it\n");
printf("so switching to telephoto spot mode.\n");
p->tele = 1;
}
- if (( p->tele && !IMODETST(cap, inst_mode_emis_tele))
- || (!p->tele && !IMODETST(cap, inst_mode_emis_spot))) {
+ if (( p->tele && p->it->check_mode(p->it, inst_mode_emis_tele) != inst_ok)
+ || (!p->tele && p->it->check_mode(p->it, inst_mode_emis_spot) != inst_ok)) {
printf("Need %s emissive measurement capability,\n", p->tele ? "telephoto" : "spot");
printf("but instrument doesn't support it\n");
a1logd(p->log,1,"Need %s emissive measurement capability but device doesn't support it,\n",
@@ -2685,7 +2698,7 @@ a1log *log /* Verb, debug & error log */
printf("Calibrate failed with '%s' (%s)\n",
p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
p->del(p);
- if (errc != NULL) *errc = 2;
+ if (errc != NULL) *errc = ((rv & inst_mask) == inst_user_abort) ? 1 : 2;
return NULL;
}
}
diff --git a/spectro/dispsup.h b/spectro/dispsup.h
index bca3070..07a66e2 100644
--- a/spectro/dispsup.h
+++ b/spectro/dispsup.h
@@ -91,9 +91,6 @@ typedef struct {
} col;
-/* Maximum number of entries to setup for calibration */
-#define MAX_CAL_ENT 4096
-
/* Display reading context */
struct _disprd {
diff --git a/spectro/disptechs.c b/spectro/disptechs.c
index 70e150f..bade777 100644
--- a/spectro/disptechs.c
+++ b/spectro/disptechs.c
@@ -22,14 +22,15 @@
#include <ctype.h>
#include <string.h>
#include <time.h>
+#include "numsup.h"
#ifndef SALONEINSTLIB
#include "copyright.h"
#include "aconfig.h"
#include "icc.h"
#else
#include "sa_config.h"
+#include "sa_conv.h"
#endif /* !SALONEINSTLIB */
-#include "numsup.h"
#include "conv.h"
#include "disptechs.h"
diff --git a/spectro/dispwin.c b/spectro/dispwin.c
index fffbaee..368f707 100644
--- a/spectro/dispwin.c
+++ b/spectro/dispwin.c
@@ -31,6 +31,10 @@
* Should add dithering support to overcome 8 bit limitations of
* non-RAMDAC access or limited RAMDAC depth. (How do we easily
* determine the latter ??)
+ *
+ * For X11/XRANDR, should we check for and save/restore CscMatrix property ??
+ * - or should we assumed that the use intends to use this to manually calibrate the display ??
+ * See <http://us.download.nvidia.com/XFree86/Linux-x86/364.12/README/xrandrextension.html#CscMatrix>
*/
#include <stdio.h>
@@ -69,7 +73,7 @@
# endif
#endif
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/*
Note that the new ColorSync API is defined in
@@ -113,14 +117,14 @@ typedef float CGFloat;
#endif
#endif /* !NSINTEGER_DEFINED */
-#include <IOKit/Graphics/IOGraphicsLib.h>
+#include <IOKit/graphics/IOGraphicsLib.h>
#if __MAC_OS_X_VERSION_MAX_ALLOWED <= 1060
/* This wasn't declared in 10.6, although it is needed */
CFUUIDRef CGDisplayCreateUUIDFromDisplayID (uint32_t displayID);
#endif /* < 10.6 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#define VERIFY_TOL (1.0/255.0)
#undef DISABLE_RANDR /* Disable XRandR code */
@@ -388,7 +392,7 @@ disppath **get_displays() {
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* Note :- some recent releases of OS X have a feature which */
/* automatically adjusts the screen brigtness with ambient level. */
/* We may have to find a way of disabling this during calibration and profiling. */
@@ -548,7 +552,7 @@ disppath **get_displays() {
}
free(dids);
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
int i, j, k;
@@ -636,8 +640,8 @@ disppath **get_displays() {
/* Look at all the screens outputs */
for (jj = j = 0; j < scrnres->noutput; j++) {
- XRROutputInfo *outi;
- XRRCrtcInfo *crtci;
+ XRROutputInfo *outi = NULL;
+ XRRCrtcInfo *crtci = NULL;
if ((outi = XRRGetOutputInfo(mydisplay, scrnres, scrnres->outputs[j])) == NULL) {
debugrr("XRRGetOutputInfo failed\n");
@@ -649,12 +653,13 @@ disppath **get_displays() {
if (outi->connection == RR_Disconnected ||
outi->crtc == None) {
+ XRRFreeOutputInfo(outi);
continue;
}
/* Check that the VideoLUT's are accessible */
{
- XRRCrtcGamma *crtcgam;
+ XRRCrtcGamma *crtcgam = NULL;
debugrr("Checking XRandR 1.2 VideoLUT access\n");
if ((crtcgam = XRRGetCrtcGamma(mydisplay, outi->crtc)) == NULL
@@ -666,8 +671,11 @@ disppath **get_displays() {
disps = NULL;
j = scrnres->noutput;
i = dcount;
+ XRRFreeOutputInfo(outi);
continue; /* Abort XRandR 1.2 */
}
+ if (crtcgam != NULL)
+ XRRFreeGamma(crtcgam);
}
#ifdef NEVER
{
@@ -692,6 +700,7 @@ disppath **get_displays() {
if ((disps = (disppath **)calloc(sizeof(disppath *), 1 + 1)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
return NULL;
@@ -701,6 +710,7 @@ disppath **get_displays() {
sizeof(disppath *) * (ndisps + 2))) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
return NULL;
@@ -711,6 +721,7 @@ disppath **get_displays() {
if ((disps[ndisps] = calloc(sizeof(disppath),1)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
free_disppaths(disps);
@@ -741,6 +752,7 @@ disppath **get_displays() {
if ((disps[ndisps]->description = strdup(desc2)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
free_disppaths(disps);
@@ -756,6 +768,7 @@ disppath **get_displays() {
if ((disps[ndisps]->name = strdup(dnbuf)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
free_disppaths(disps);
@@ -809,6 +822,7 @@ disppath **get_displays() {
if ((disps[ndisps]->edid = malloc(sizeof(unsigned char) * ret_len)) == NULL) {
debugrr("get_displays failed on malloc\n");
XRRFreeCrtcInfo(crtci);
+ XRRFreeOutputInfo(outi);
XRRFreeScreenResources(scrnres);
XCloseDisplay(mydisplay);
free_disppaths(disps);
@@ -833,7 +847,6 @@ disppath **get_displays() {
}
XRRFreeOutputInfo(outi);
}
-
XRRFreeScreenResources(scrnres);
}
XSetErrorHandler(NULL);
@@ -1136,15 +1149,16 @@ void free_a_disppath(disppath *path) {
/* ----------------------------------------------- */
-/* For VideoLUT/RAMDAC use, we assume that the number of entries in the RAMDAC */
-/* meshes perfectly with the display raster depth, so that we can */
-/* figure out how to apportion device values. We fail if they don't */
-/* seem to mesh. */
+/* For VideoLUT/RAMDAC use, we assume that the frame buffer */
+/* may map through some intermediate hardware or lookup */
+/* into a RAMDAC index. */
/* !!! Would be nice to add an error message return to dispwin and */
/* !!! pass errors back to it so that the detail can be reported */
/* !!! to the user. */
+static void dispwin_dump_ramdac(FILE *fp, ramdac *r);
+
/* Get RAMDAC values. ->del() when finished. */
/* Return NULL if not possible */
static ramdac *dispwin_get_ramdac(dispwin *p) {
@@ -1168,9 +1182,11 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
debugr("dispwin_get_ramdac failed on malloc()\n");
return NULL;
}
- r->pdepth = p->pdepth;
- r->nent = (1 << p->pdepth);
- r->clone = dispwin_clone_ramdac;
+ r->fdepth = p->fdepth;
+ r->rdepth = p->rdepth;
+ r->ndepth = p->ndepth;
+ r->nent = p->nent;
+ r->clone = dispwin_clone_ramdac;
r->setlin = dispwin_setlin_ramdac;
r->del = dispwin_del_ramdac;
@@ -1186,9 +1202,9 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
}
/* GetDeviceGammaRamp() is hard coded for 3 x 256 entries (Quantize) */
- if (r->nent != 256) {
+ if (256 != r->nent) {
free(r);
- debugr2((errout,"GetDeviceGammaRamp() is hard coded for nent == 256, and we've got nent = %d!\n",r->nent));
+ debugr2((errout,"GetDeviceGammaRamp number of entries %d inconsistent with expected value %d\n",256,p->nent));
return NULL;
}
@@ -1204,7 +1220,7 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
unsigned int nent;
CGGammaValue vals[3][16385];
@@ -1220,8 +1236,8 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return NULL;
}
- if (nent != (1 << p->pdepth)) {
- debugr2((errout,"CGGetDisplayTransferByTable number of entries %d mismatches screen depth %d\n",nent,p->pdepth));
+ if (nent != p->nent) {
+ debugr2((errout,"CGGetDisplayTransferByTable number of entries %u inconsistent with previous value %d\n",nent,p->nent));
return NULL;
}
@@ -1231,8 +1247,10 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return NULL;
}
- r->pdepth = p->pdepth;
- r->nent = (1 << p->pdepth);
+ r->fdepth = p->fdepth;
+ r->rdepth = p->rdepth;
+ r->ndepth = p->ndepth;
+ r->nent = p->nent;
r->clone = dispwin_clone_ramdac;
r->setlin = dispwin_setlin_ramdac;
r->del = dispwin_del_ramdac;
@@ -1252,7 +1270,7 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
r->v[j][i] = vals[j][i];
}
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
unsigned short vals[3][16384];
@@ -1275,13 +1293,8 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
nent = crtcgam->size;
- if (nent > 16384) {
- debugr("XRRGetCrtcGammaSize has more entries than we can handle\n");
- return NULL;
- }
-
- if (nent != (1 << p->pdepth)) {
- debugr2((errout,"XRRGetCrtcGammaSize number of entries %d mismatches screen depth %d bits\n",nent,(1 << p->pdepth)));
+ if (nent != p->nent) {
+ debugr2((errout,"XRRGetCrtcGammaSize number of entries %d inconsistent with previous value\n",nent,p->nent));
return NULL;
}
@@ -1331,8 +1344,8 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return NULL;
}
- if (nent > 16384) {
- debugr("XF86VidModeGetGammaRampSize has more entries than we can handle\n");
+ if (nent != p->nent) {
+ debugr2((errout,"XF86VidModeGetGammaRampSize number of entries %d inconsistent with previous value\n",nent,p->nent));
return NULL;
}
@@ -1340,11 +1353,6 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
debugr("XF86VidModeGetGammaRamp failed\n");
return NULL;
}
-
- if (nent != (1 << p->pdepth)) {
- debugr2((errout,"CGGetDisplayTransferByTable number of entries %d mismatches screen depth %d bits\n",nent,(1 << p->pdepth)));
- return NULL;
- }
}
/* Allocate a ramdac */
@@ -1353,9 +1361,11 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return NULL;
}
- r->pdepth = p->pdepth;
- r->nent = (1 << p->pdepth);
- r->clone = dispwin_clone_ramdac;
+ r->fdepth = p->fdepth;
+ r->rdepth = p->rdepth;
+ r->ndepth = p->ndepth;
+ r->nent = p->nent;
+ r->clone = dispwin_clone_ramdac;
r->setlin = dispwin_setlin_ramdac;
r->del = dispwin_del_ramdac;
for (j = 0; j < 3; j++) {
@@ -1379,7 +1389,7 @@ static ramdac *dispwin_get_ramdac(dispwin *p) {
return r;
}
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* Various support functions */
#if __MAC_OS_X_VERSION_MAX_ALLOWED < 1060
@@ -1643,7 +1653,7 @@ static void *cur_colorsync_ref(dispwin *p) {
return cspr;
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* Set the RAMDAC values. */
/* Return nz if not possible */
@@ -1666,6 +1676,7 @@ static int dispwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
for (j = 0; j < 3; j++) {
for (i = 0; i < r->nent; i++) {
double vv = r->v[j][i];
+
if (vv < 0.0)
vv = 0.0;
else if (vv > 1.0)
@@ -1676,12 +1687,15 @@ static int dispwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
if (SetDeviceGammaRamp(p->hdc, vals) == 0) {
debugr2((errout,"dispwin_set_ramdac failed on SetDeviceGammaRamp() with error %d\n",GetLastError()));
+#ifdef NEVER
+ dispwin_dump_ramdac(stderr, r);
+#endif
return 1;
}
GdiFlush();
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
{ /* Transient first */
CGGammaValue vals[3][16384];
@@ -2115,7 +2129,7 @@ static int dispwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
}
#endif /* < 10.6 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
unsigned short vals[3][16384];
@@ -2214,6 +2228,24 @@ ramdac *dispwin_clone_ramdac(ramdac *r) {
return nr;
}
+/* Debug dump ramdac */
+static void dispwin_dump_ramdac(FILE *fp, ramdac *r) {
+ int i, j;
+
+ fprintf(fp,"Ramdac fdepth %d, rdepth %d, ndepth %d, nent %d\n",
+ r->fdepth, r->rdepth, r->ndepth, r->nent);
+
+ for (i = 0; i < r->nent; i++) {
+ int note = 0;
+ for (j = 0; j < 3; j++) {
+ if (r->v[j][i] < 0.0 || r->v[j][i] > 1.0
+ || (i > 0 && r->v[j][i] < r->v[j][i-1]))
+ note = 1;
+ }
+ fprintf(fp," %d: %f %f %f%s\n",i, r->v[0][i], r->v[1][i], r->v[2][i], note ? " #" : "");
+ }
+}
+
/* Set the ramdac values to linear */
void dispwin_setlin_ramdac(ramdac *r) {
int i, j;
@@ -2522,7 +2554,7 @@ int dispwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
}
#endif /* OS X || Linux */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
@@ -2685,7 +2717,7 @@ int dispwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
return 0;
}
#endif /* 10.6 and prior */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11) && defined(USE_UCMM)
{
@@ -2862,7 +2894,7 @@ int dispwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
}
}
#endif /* OS X || Linux */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
{
char *dpath; /* Un-install file path */
@@ -2980,7 +3012,7 @@ int dispwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
return 0;
}
#endif /* 10.6 and prior */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11) && defined(USE_UCMM)
{
@@ -3043,7 +3075,7 @@ icmFile *dispwin_get_profile(dispwin *p, char *name, int mxlen) {
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
char *dpath; /* Read file path */
@@ -3187,7 +3219,7 @@ icmFile *dispwin_get_profile(dispwin *p, char *name, int mxlen) {
return rd_fp;
}
#endif /* 10.5 and prior */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11) && defined(USE_UCMM)
/* Try and get the currently installed profile from ucmm */
@@ -3454,7 +3486,7 @@ static void dispwin_uninstall_signal_handlers(dispwin *p) {
/* ----------------------------------------------- */
/* Test patch window specific declarations */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
@class DWWin;
@class DWView;
@@ -3467,6 +3499,8 @@ typedef struct {
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
NSColorSpace *nscs; /* Colorspace from profile */
#endif
+ NSRect rect; /* Size and position to create window */
+ int err; /* Error code */
} osx_cntx_t;
// - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -3545,6 +3579,15 @@ unsigned char emptyCursor[43] = {
@end
+/* Function called back by main thread to trigger a drawRect */
+
+static void doSetNeedsDisplay(void *cntx) {
+ osx_cntx_t *cx = (osx_cntx_t *)cntx;
+
+ [cx->view setNeedsDisplay: YES ];
+
+ cx->err = 0;
+}
// - - - - - - - - - - - - - - - - - - - - - - - - -
@interface DWWin : NSWindow {
@@ -3582,7 +3625,9 @@ unsigned char emptyCursor[43] = {
@end
/* Create our window */
-static void create_my_win(NSRect rect, osx_cntx_t *cx) {
+/* We run this on the main thread using a custom message */
+static void create_my_win(void *cntx) {
+ osx_cntx_t *cx = (osx_cntx_t *)cntx;
dispwin *p = cx->p;
SInt32 MacMajVers, MacMinVers, MacBFVers;
void *cspr = NULL; /* ColorSync profile ref. */
@@ -3607,7 +3652,7 @@ static void create_my_win(NSRect rect, osx_cntx_t *cx) {
}
/* Create Window */
- cx->window = [[DWWin alloc] initWithContentRect: rect
+ cx->window = [[DWWin alloc] initWithContentRect: cx->rect
styleMask: NSBorderlessWindowMask
backing: NSBackingStoreBuffered
defer: YES
@@ -3626,7 +3671,8 @@ static void create_my_win(NSRect rect, osx_cntx_t *cx) {
/* Moves the window to the front of the screen list within its level, */
/* and show the window (i.e. make it "key") */
- /* Trigger crash on OS X 10.11 El Capitan ? */
+ /* Trigger warning on OS X 10.11 El Capitan ? */
+ /* (Doesn't happen using 1.6.3 which ran everything in the main thread.) */
[cx->window makeKeyAndOrderFront: nil];
/* Use a null color transform to ensure device values */
@@ -3686,9 +3732,10 @@ static void create_my_win(NSRect rect, osx_cntx_t *cx) {
}
#endif
+ cx->err = 0;
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* ----------------------------------------------- */
@@ -3726,22 +3773,24 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
/* For video encoding the extra bits of precision are created by bit shifting */
/* rather than scaling, so we need to scale the fp value to account for this. */
- if (p->pdepth > 8)
- p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->pdepth - 8)))
- /((1 << p->pdepth) - 1.0);
+ if (p->edepth > 8)
+ p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->edepth - 8)))
+ /((1 << p->edepth) - 1.0);
}
}
//if (p->out_tvenc) {
//printf(" %d: 8 bit tv = s_rgb %f %f %f\n",j, p->s_rgb[0], p->s_rgb[1], p->s_rgb[2]);
-//printf(" %d: %d bitraster r_rgb %f %f %f\n",j, p->pdepth,p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]);
+//printf(" %d: %d bitraster r_rgb %f %f %f\n",j, p->edepth,p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]);
//}
/* Use ramdac for high precision native output. */
/* The ramdac is used to hold the lsb that the frame buffer */
/* doesn't hold. */
if ((p->native & 1) == 1) {
- double prange = p->r->nent - 1.0;
+ double frange = (1 << p->fdepth) - 1.0;
+ double rrange = (1 << p->rdepth) - 1.0;
+ double nrange = p->nent - 1.0;
p->r->setlin(p->r); /* In case something else altered this */
@@ -3756,9 +3805,66 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
if (p->out_tvenc && p->edepth > 8)
vv = (vv * 255 * (1 << (p->edepth - 8)))/((1 << p->edepth) - 1.0);
- tt = (int)(vv * prange + 0.5);
- p->r_rgb[j] = (double)tt/prange; /* RAMDAC output Quantized value */
+ /* Determine the ramdac index that the quantized frame buffer */
+ /* value will make use of */
+#ifdef NT
+ /* Assume all depths match, or linear mapping between them */
+ tt = (int)(vv * frange + 0.5); /* Frame buffer value */
+ p->r_rgb[j] = (double)tt/frange; /* Double frame buffer value */
+ tt = (int)(tt/frange * rrange + 0.5); /* expected RAMDAC index */
+ tt = (int)(tt/rrange * nrange + 0.5); /* actual RAMDAC index */
+#endif
+#ifdef UNIX_APPLE
+ /* We assume linear mapping with perfect rounding between rdepth and ndepth */
+ tt = (int)(vv * frange + 0.5); /* Frame buffer value */
+ p->r_rgb[j] = (double)tt/frange; /* Double frame buffer value */
+ tt = (int)(tt/frange * rrange + 0.5); /* expected RAMDAC index */
+ tt = (int)(tt/rrange * nrange + 0.5); /* actual RAMDAC index */
+#endif
+#if defined(UNIX_X11)
+ /* We assume linear mapping with perfect rounding between rdepth and ndepth */
+ tt = (int)(vv * frange + 0.5); /* Frame buffer value */
+ p->r_rgb[j] = (double)tt/frange; /* Double frame buffer value */
+ tt = p->rmap[j][tt]; /* expected RAMDAC index */
+ tt = (int)(tt/rrange * nrange + 0.5); /* actual RAMDAC index */
+#endif
+
+#ifdef NEVER // Just set entry we think will get hit
p->r->v[j][tt] = vv;
+#else
+
+ /* Set the three entries around target and create ramp either side,
+ to allow for some video cards not having a precise
+ definition of what value translates to what frame buffer value. */
+ {
+ int i;
+ double maxv = 1.0;
+
+ if (p->out_tvenc && p->edepth > 8)
+ maxv = (maxv * 255 * (1 << (p->edepth - 8)))/((1 << p->edepth) - 1.0);
+
+ if ((tt-1) == 0) {
+ p->r->v[j][tt-1] = vv;
+ } else {
+ for (i = 0; i <= (tt-1); i++)
+ p->r->v[j][i] = vv * i/(tt-1);
+ }
+
+ p->r->v[j][tt] = vv;
+
+ if ((tt+1) == (p->r->nent-1)) {
+ p->r->v[j][tt+1] = vv;
+ } else {
+ for (i = tt+1; i < p->r->nent; i++)
+ p->r->v[j][i] = vv + (maxv - vv) * (i - (tt+1))/((p->r->nent-1) - (tt+1));
+ }
+
+#ifdef NEVER
+ for (i = 0; i < p->r->nent; i++)
+ printf("~1 %d, %d -> %f\n",j,i,p->r->v[j][i]);
+#endif
+ }
+#endif
//printf(" cell[%d] = r_rgb %f, cell val %f\n",tt, p->r_rgb[j], vv);
}
@@ -3796,7 +3902,9 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
#endif
p->colupd++;
-//printf("~1 set color %f %f %f\n", p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]);
+
+ debugr2((errout,"dispwin_set_color about to paint color %f %f %f\n",
+ p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]));
/* Trigger a WM_PAINT */
if (!InvalidateRect(p->hwnd, NULL, FALSE)) {
@@ -3810,13 +3918,14 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
while (p->colupd != p->colupde && p->cberror == 0) {
msec_sleep(10);
}
-//printf("~1 paint done\n");
+
+ debugr2((errout,"dispwin_set_color paint done\n"));
}
#endif /* NT */
/* - - - - - - - - - - - - - - */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
if (p->winclose) {
return 2;
@@ -3840,11 +3949,7 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
if ((stat = GetCurrentProcess(&cpsn)) != noErr) {
debugr2((errout,"GetCurrentProcess returned error %d\n",stat));
} else {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
- if ((stat = TransformProcessType(&cpsn, kProcessTransformToForegroundApplication)) != noErr) {
- debugr2((errout,"TransformProcessType returned error %d\n",stat));
- }
-#endif /* OS X 10.3 */
+ // [window makeGetAndOrderFront:] ??
if ((stat = SetFrontProcess(&cpsn)) != noErr) {
debugr2((errout,"SetFrontProcess returned error %d\n",stat));
}
@@ -3852,40 +3957,56 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
p->btf = 1;
}
- /* Trigger an update that fills window with r_rgb[] */
- [((osx_cntx_t *)(p->osx_cntx))->view setNeedsDisplay: YES ];
+ /* Prepare to wait for events */
+ ui_aboutToWait();
+
+ debugr2((errout,"dispwin_set_color about to paint color %f %f %f\n",
+ p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]));
+
+// [((osx_cntx_t *)(p->osx_cntx))->view setNeedsDisplay: YES ];
+
+ /* Run the window creation in the main thread and wait for it */
+ ui_runInMainThreadAndWait((void *)p->osx_cntx, doSetNeedsDisplay);
+
+ /* Wait for any events generated by paint to complete */
+ ui_waitForEvents();
+
+ debugr2((errout,"dispwin_set_color paint done\n"));
if (tpool != nil)
[tpool release];
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* - - - - - - - - - - - - - - */
#if defined(UNIX_X11)
{
- Colormap mycmap;
- XColor col;
- int vali[3];
+ unsigned int vali[3];
+ unsigned long fbval;
/* Indicate that we've got activity to the X11 Screensaver */
XResetScreenSaver(p->mydisplay);
- /* Quantize to 16 bit color */
+ /* Quantize to frame buffer component depth */
for (j = 0; j < 3; j++)
- vali[j] = (int)(65535.0 * p->r_rgb[j] + 0.5);
+ vali[j] = (int)(((1 << p->fdepth)-1.0) * p->r_rgb[j] + 0.5);
- mycmap = DefaultColormap(p->mydisplay, p->myscreen);
- col.red = vali[0];
- col.green = vali[1];
- col.blue = vali[2];
- XAllocColor(p->mydisplay, mycmap, &col);
- XSetForeground(p->mydisplay, p->mygc, col.pixel);
+ /* Compose frame buffer pixel value */
+ fbval = (vali[0] << p->shift[0])
+ | (vali[1] << p->shift[1])
+ | (vali[2] << p->shift[2]);
+ XSetForeground(p->mydisplay, p->mygc, fbval);
+
+ debugr2((errout,"dispwin_set_color about to paint color %f %f %f\n",
+ p->r_rgb[0], p->r_rgb[1], p->r_rgb[2]));
XFillRectangle(p->mydisplay, p->mywindow, p->mygc,
p->tx, p->ty, p->tw, p->th);
XSync(p->mydisplay, False); /* Make sure it happens */
+
+ debugr2((errout,"dispwin_set_color paint done\n"));
}
#endif /* UNXI X11 */
@@ -4029,6 +4150,7 @@ dispwin *p
if (p->mth != NULL) { /* Message thread */
p->mth->del(p->mth);
}
+ p->hwnd = NULL;
}
if (p->hdc != NULL)
@@ -4038,7 +4160,7 @@ dispwin *p
/* -------------------------------------------------- */
/* -------------------------------------------------- */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
if (p->nowin == 0) { /* We have a window up */
restore_display(p);
if (p->osx_cntx != NULL) { /* And we've allocated a context */
@@ -4061,7 +4183,7 @@ dispwin *p
// ~~
// CGDisplayShowCursor(p->ddid);
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* -------------------------------------------------- */
/* -------------------------------------------------- */
@@ -4071,22 +4193,43 @@ dispwin *p
if (p->mydisplay != NULL) {
if (p->nowin == 0) { /* We have a window up */
- XFreeGC(p->mydisplay, p->mygc);
- XDestroyWindow(p->mydisplay, p->mywindow);
+ if (p->mygc != 0)
+ XFreeGC(p->mydisplay, p->mygc);
+ if (p->mywindow != 0)
+ XDestroyWindow(p->mydisplay, p->mywindow);
}
XCloseDisplay(p->mydisplay);
+ p->mydisplay = NULL;
+ }
+ {
+ int j;
+ for (j = 0; j < 3; j++) {
+ if (p->rmap[j] != NULL) {
+ free(p->rmap[j]);
+ p->rmap[j] = NULL;
+ }
+ }
}
debugr("finished\n");
+ if (p->edid != NULL)
+ free(p->edid);
+
#endif /* UNXI X11 */
/* -------------------------------------------------- */
- if (p->name != NULL)
+ if (p->name != NULL) {
free(p->name);
- if (p->description != NULL)
+ p->name = NULL;
+ }
+ if (p->description != NULL) {
free(p->description);
- if (p->callout != NULL)
+ p->description = NULL;
+ }
+ if (p->callout != NULL) {
free(p->callout);
+ p->callout = NULL;
+ }
free(p);
}
@@ -4234,6 +4377,10 @@ static LRESULT CALLBACK MainWndProc(
#endif /* NT */
+#ifdef UNIX_APPLE
+
+#endif /* UNIX_APPLE */
+
#if defined(UNIX_X11)
/* None */
#endif /* UNXI X11 */
@@ -4241,7 +4388,8 @@ static LRESULT CALLBACK MainWndProc(
/* ----------------------------------------------- */
#ifdef NT
-/* Thread to handle message processing, so that there is no delay */
+/* Thread to create the window if it doesn'r exist, */
+/* and handle message processing, so that there is no delay */
/* when the main thread is doing other things. */
int win_message_thread(void *pp) {
dispwin *p = (dispwin *)pp;
@@ -4333,7 +4481,7 @@ int win_message_thread(void *pp) {
}
if (UnregisterClass(p->AppName, NULL) == 0) {
- warning("UnregisterClass failed, lasterr = %d\n",GetLastError());
+ warning("UnregisterClass failed, lasterr = %d",GetLastError());
}
p->hwnd = NULL; /* Signal it's been deleted */
@@ -4400,7 +4548,10 @@ int ddebug /* >0 to print debug statements to stderr */
) {
dispwin *p = NULL;
- debug("new_dispwin called\n");
+#ifndef DEBUG
+ if (ddebug)
+#endif
+ fprintf(errout, "new_dispwin called\n");
#if defined(UNIX_X11) && defined(USE_UCMM)
dispwin_checkfor_colord(); /* Make colord functions available */
@@ -4444,6 +4595,8 @@ int ddebug /* >0 to print debug statements to stderr */
/* Basic object is initialised, so create a window */
+ ui_UsingGUI();
+
/* -------------------------------------------------- */
#ifdef NT
{
@@ -4511,7 +4664,7 @@ int ddebug /* >0 to print debug statements to stderr */
p->wh = he;
/* It's a bit difficult to know how windows defines the display */
- /* depth. Microsofts doco is fuzzy, and typical values */
+ /* depth. Microsoft's doco is fuzzy, and typical values */
/* for BITSPIXEL and PLANES are confusing (What does "32" and "1" */
/* mean ?) NUMCOLORS seems to be -1 on my box, and perhaps */
/* is only applicable to up to 256 paletized colors. The doco */
@@ -4530,12 +4683,17 @@ int ddebug /* >0 to print debug statements to stderr */
}
bpp = GetDeviceCaps(p->hdc, COLORRES);
if (bpp <= 0)
- p->pdepth = 8; /* Assume this is so */
+ p->fdepth = 8; /* Assume this is so */
else
- p->pdepth = bpp/3;
+ p->fdepth = bpp/3;
+ p->rdepth = p->fdepth; /* Assume this is so */
+ p->ndepth = 8; /* Assume this is so */
+ p->nent = (1 << p->ndepth);
p->edepth = 16;
+ debugr2((errout,"new_dispwin: fdepth %d, rdepth %d, ndepth %d, edepth %d\n", p->fdepth,p->rdepth,p->ndepth,p->edepth));
+
if (nowin == 0) {
/* We use a thread to process the window messages, so that */
@@ -4549,6 +4707,9 @@ int ddebug /* >0 to print debug statements to stderr */
p->wi = wi;
p->he = he;
+ debugr2((errout,"new_dispwin about to create window\n"));
+
+ /* Create the window and then process events */
if ((p->mth = new_athread(win_message_thread, (void *)p)) == NULL) {
debugr2((errout, "new_dispwin: new_athread failed\n"));
dispwin_del(p);
@@ -4556,6 +4717,9 @@ int ddebug /* >0 to print debug statements to stderr */
}
/* Wait for thread to run */
+ /* (Hmm. This doesn't actually gurantee that our window has */
+ /* been created yet ? */
+ // ~~ should sync by sending a custom message and getting notified ? */
while (p->inited == 0) {
msec_sleep(20);
}
@@ -4565,6 +4729,8 @@ int ddebug /* >0 to print debug statements to stderr */
dispwin_del(p);
return NULL;
}
+
+ debugr2((errout,"new_dispwin window created\n"));
}
/* Install the signal handler to ensure cleanup */
@@ -4575,7 +4741,7 @@ int ddebug /* >0 to print debug statements to stderr */
/* -------------------------------------------------- */
/* -------------------------------------------------- */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
if ((p->name = strdup(disp->name)) == NULL) {
debugr2((errout,"new_dispwin: Malloc failed\n"));
@@ -4584,31 +4750,13 @@ int ddebug /* >0 to print debug statements to stderr */
}
p->ddid = disp->ddid; /* Display we're working on */
- /* Hmm. Could we use CGDisplayGammaTableCapacity() instead ? */
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
CGDisplayModeRef dispmode;
CFStringRef pixenc;
- int cap = CGDisplayGammaTableCapacity(p->ddid);
int fbdepth = 0;
- debugr2((errout,"new_dispwin: CGDisplayGammaTableCapacity = %d\n",cap));
-
- /* Compute GammaTable depth */
- {
- for (p->pdepth = 1; p->pdepth < 17; p->pdepth++) {
- if ((1 << p->pdepth) == cap)
- break;
- }
- if (p->pdepth >= 17) {
- debugr2((errout,"new_dispwin: failed to extract depth from GammaTableCapacity %d\n",cap));
- dispwin_del(p);
- return NULL;
- }
- debugr2((errout,"new_dispwin: found pixel depth %d bits\n",p->pdepth));
- }
- /* Get frame buffer depth for sanity check, but don't actually make used of it */
-
+ /* Get frame buffer depth */
dispmode = CGDisplayCopyDisplayMode(p->ddid);
pixenc = CGDisplayModeCopyPixelEncoding(dispmode);
@@ -4625,6 +4773,9 @@ int ddebug /* >0 to print debug statements to stderr */
else if (CFStringCompare(pixenc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive)
== kCFCompareEqualTo)
fbdepth = 5;
+ else
+ fbdepth = 8; /* Assume */
+
#ifndef DEBUG
if (p->ddebug)
#endif
@@ -4637,26 +4788,56 @@ int ddebug /* >0 to print debug statements to stderr */
CFRelease(pixenc);
CGDisplayModeRelease(dispmode);
- if (p->pdepth != fbdepth) {
- static int warned = 0;
- if (!warned) {
- warning("new_dispwin: frame buffer depth %d != GammaTable depth %d\n",fbdepth, p->pdepth);
- warned = 1;
+ p->fdepth = fbdepth;
+ p->rdepth = p->fdepth; /* We don't know of any HW between frame buffer and VideoLUT */
+
+ /* Get CGDisplayGammaTable size */
+ p->nent = CGDisplayGammaTableCapacity(p->ddid);
+
+ /* Compute GammaTable/VideoLUT/RAMDAC depth */
+ {
+ for (p->ndepth = 1; p->ndepth < 17; p->ndepth++) {
+ if ((1 << p->ndepth) >= p->nent)
+ break;
+ }
+ if (p->ndepth >= 17) {
+ debugr2((errout,"new_dispwin: failed to extract depth from GammaTableCapacity %d\n",p->nent));
+ dispwin_del(p);
+ return NULL;
+ }
+ debugr2((errout,"new_dispwin: found actual VideoLUT depth %d bits\n",p->ndepth));
+ }
+
+ if (p->rdepth > p->ndepth) {
+ debugr2((errout,"new_dispwin: Frame buffer depth %d > VideoLUT depth %d\n",p->rdepth, p->ndepth));
+ dispwin_del(p);
+ return NULL;
+ }
+
+ if (p->rdepth != p->ndepth) {
+ if (!p->warned) {
+ warning("new_dispwin: Frame buffer depth %d doesn't matcv VideoLUT %d",p->rdepth, p->ndepth);
+ p->warned = 1;
}
}
}
#else
- p->pdepth = CGDisplayBitsPerSample(p->ddid);
+ /* Life is simple */
+ p->fdepth = CGDisplayBitsPerSample(p->ddid);
+ p->rdepth = p->fdepth;
+ p->ndepth = p->rdepth;
+ p->nent = (1 << p->ndepth);
#endif
p->edepth = 16; /* By experiment it seems to be 16 bits too */
+ debugr2((errout,"new_dispwin: fdepth %d, rdepth %d, ndepth %d, edepth %d\n", p->fdepth,p->rdepth,p->ndepth,p->edepth));
+
if (nowin == 0) { /* Create a window */
osx_cntx_t *cx;
CGSize sz; /* Display size in mm */
int wi, he; /* Width and height in pixels */
int xo, yo; /* Window location */
- NSRect wrect;
debugr2((errout, "new_dispwin: About to open display '%s'\n",disp->name));
@@ -4716,22 +4897,33 @@ int ddebug /* >0 to print debug statements to stderr */
p->ww = wi;
p->wh = he;
- wrect.origin.x = xo;
- wrect.origin.y = yo;
- wrect.size.width = wi;
- wrect.size.height = he;
+ cx->rect.origin.x = xo;
+ cx->rect.origin.y = yo;
+ cx->rect.size.width = wi;
+ cx->rect.size.height = he;
+
+ debugr2((errout,"new_dispwin about to create window\n"));
+
+ /* Prepare to wait for events */
+ ui_aboutToWait();
- create_my_win(wrect, cx);
+ /* Run the window creation in the main thread and wait for it */
+ ui_runInMainThreadAndWait((void *)cx, create_my_win);
+
+ /* Wait for events generated by window creation to complete */
+ ui_waitForEvents();
if (tpool != nil)
[tpool release];
p->winclose = 0;
+
+ debugr2((errout,"new_dispwin window created\n"));
}
/* Install the signal handler to ensure cleanup */
dispwin_install_signal_handlers(p);
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* -------------------------------------------------- */
/* -------------------------------------------------- */
@@ -4755,6 +4947,8 @@ int ddebug /* >0 to print debug statements to stderr */
Window rootwindow;
char *appname = "TestWin";
Visual *myvisual;
+ XVisualInfo template, *vinfo;
+ int nitems = 0;
XSetWindowAttributes myattr;
XEvent myevent;
XTextProperty myappname;
@@ -4817,15 +5011,184 @@ int ddebug /* >0 to print debug statements to stderr */
memmove(p->edid, disp->edid, p->edid_len);
}
- //p->pdepth = DefaultDepth(p->mydisplay, p->myscreen)/3;
+#ifdef NEVER
+#pragma message("######### dispwin.c DirectColor test is defined! ########")
+
+ /* To test DirectColor Visual when it's not the default:*/
+ debugr2((errout,"new_dispwin: Testing DirectColor Visual\n"));
+
+ // test DirectColor visual
+ template.class = DirectColor;
+ if ((vinfo = XGetVisualInfo(p->mydisplay, VisualClassMask, &template, &nitems)) == NULL) {
+ debugr2((errout,"new_dispwin: Unable to find a DirectColor Visual\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ myvisual = vinfo->visual;
- // Hmm. Should we explicitly get the root window visual,
- // since our test window inherits it from root ?
+#else
myvisual = DefaultVisual(p->mydisplay, p->myscreen);
- p->pdepth = myvisual->bits_per_rgb;
- p->edepth = 16;
+#endif
+
+ /* Expect TrueColor (fixed/no map) or DirectColor (read/write map) Visual - */
+ /* anything else is not suitable for high quality color. */
+
+ /* Get the VisualInfo */
+ template.visualid = myvisual->visualid;
+ vinfo = XGetVisualInfo(p->mydisplay, VisualIDMask, &template, &nitems);
+
+ if (nitems < 1) {
+ debugr2((errout,"new_dispwin: Failed to get XGetVisualInfo of defalt Visual\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+
+ if (vinfo->class != TrueColor && vinfo->class != DirectColor) {
+ debugr2((errout,"new_dispwin: Default Visual is not TrueColor or DirectColor\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Compute per component frame buffer depth */
+ {
+ for (p->fdepth = 1; p->fdepth < 17; p->fdepth++) {
+ if ((1 << p->fdepth) >= myvisual->map_entries)
+ break;
+ }
+ if (p->fdepth >= 17) {
+ debugr2((errout,"new_dispwin: failed to extract depth from Visual bits_per_rgb %d\n",myvisual->map_entries));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ }
+ p->rdepth = myvisual->bits_per_rgb; /* X11 colormap entry size */
+ p->edepth = 16; /* Assumed */
+
+ /* Check that vinfo->red_mask, green_mask & blue_mask all have */
+ /* myvisual->map_entries number of bits set, and determine the shift. */
+ {
+ unsigned long bit;
+ int depth;
+
+ if (vinfo->red_mask == 0 || vinfo->green_mask == 0 || vinfo->blue_mask == 0) {
+ debugr2((errout,"new_dispwin: one of default Visual r/g/b masks is 0\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ for (p->shift[0] = 0, bit = 1; (bit & vinfo->red_mask) == 0; p->shift[0]++, bit <<= 1)
+ ;
+
+ for (depth = 0; (bit & vinfo->red_mask) != 0; depth++, bit <<= 1)
+ ;
+
+ if (depth != p->fdepth) {
+ debugr2((errout,"new_dispwin: Default Visual red mask 0x%x is not %d bits\n",vinfo->red_mask,p->fdepth));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ for (p->shift[1] = 0, bit = 1; (bit & vinfo->green_mask) == 0; p->shift[1]++, bit <<= 1)
+ ;
+
+ for (depth = 0; (bit & vinfo->green_mask) != 0; depth++, bit <<= 1)
+ ;
+
+ if (depth != p->fdepth) {
+ debugr2((errout,"new_dispwin: Default Visual green mask 0x%x is not %d bits\n",vinfo->red_mask,p->fdepth));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ for (p->shift[2] = 0, bit = 1; (bit & vinfo->blue_mask) == 0; p->shift[2]++, bit <<= 1)
+ ;
+
+ for (depth = 0; (bit & vinfo->blue_mask) != 0; depth++, bit <<= 1)
+ ;
+
+ if (depth != p->fdepth) {
+ debugr2((errout,"new_dispwin: Default Visual blue mask 0x%x is not %d bits\n",vinfo->red_mask,p->fdepth));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ }
+
+ /* Check the VideoLUT depth */
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ if (p->crtc != 0) { /* Using Xrandr 1.2 */
+
+ if ((p->nent = XRRGetCrtcGammaSize(p->mydisplay, p->crtc)) <= 0) {
+ p->nent = 0;
+ }
+ } else
+#endif /* randr >= V 1.2 */
+ {
+ p->nent = 0;
+
+ if (XF86VidModeQueryExtension(p->mydisplay, &evb, &erb) != 0) {
+ int nent = -1;
+
+ /* Some propietary multi-screen drivers (ie. TwinView & MergedFB) */
+ /* don't implement the XVidMode extenstion properly. */
+ if (XSetErrorHandler(null_error_handler) == 0) {
+ debugr("new_dispwin failed on XSetErrorHandler\n");
+ XSetErrorHandler(NULL); /* Restore handler */
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ if (XF86VidModeGetGammaRampSize(p->mydisplay, p->myrscreen, &nent) != 0
+ && nent != -1) {
+ p->nent = nent;
+ }
+ XSetErrorHandler(NULL); /* Restore handler */
+ }
+ }
+
+ if (p->nent == 0) {
+ p->ndepth = 0;
+
+ if (!p->warned) {
+ warning("new_dispwin: VideoLUT is not accessible");
+ p->warned = 1;
+ }
+
+ } else {
+ if (p->nent > 16384) {
+ debugr("VideoLUT has more entries than we can handle\n");
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Compute actual ramdac depth */
+ for (p->ndepth = 1; p->ndepth < 17; p->ndepth++) {
+ if ((1 << p->ndepth) >= p->nent)
+ break;
+ }
+
+ if (p->nent != (1 << p->rdepth)) {
+ if (!p->warned) {
+ warning("new_dispwin: Expected VideoLUT depth %d doesn't match actual %d",p->rdepth, p->ndepth);
+ p->warned = 1;
+ }
+ }
+ }
+
+ debugr2((errout,"new_dispwin: %s fdepth %d, rdepth %d, ndepth %d, edepth %d, r/g/b shifts %d %d %d\n", vinfo->class != TrueColor ? "TreuColor" : "DirectColor", p->fdepth,p->rdepth,p->ndepth,p->edepth, p->shift[0], p->shift[1], p->shift[2]));
if (nowin == 0) { /* Create a window */
+ unsigned long attrmask = 0;
+ XWindowAttributes mywa;
+ Colormap mycmap = None;
+ int ncolors, i;
+
rootwindow = RootWindow(p->mydisplay, p->myscreen);
myforeground = BlackPixel(p->mydisplay, p->myscreen);
@@ -4887,6 +5250,53 @@ int ddebug /* >0 to print debug statements to stderr */
else
myattr.override_redirect = False;
+ attrmask |= CWBackPixel | CWBitGravity /* Attributes Valumask */
+ | CWWinGravity | CWBackingStore | CWOverrideRedirect;
+
+ /* For a DirectColor Visual, set the X11 color map */
+ if (vinfo->class == DirectColor) {
+ Colormap mycmap = None;
+ XColor *colors;
+ int ncolors = (1 << p->fdepth), i;
+
+ debugr2((errout,"new_dispwin: setting DirectColor colormap\n"));
+
+ if ((mycmap = XCreateColormap(p->mydisplay, rootwindow, myvisual, AllocAll)) == None) {
+ debugr2((errout,"new_dispwin: XCreateColormap failed\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ if ((colors = malloc(sizeof(XColor) * ncolors)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed for XColors\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Set a linear mapping */
+ for (i = 0; i < ncolors; i++) {
+ colors[i].pixel = i << p->shift[0] | i << p->shift[1] | i << p->shift[2];
+ colors[i].red =
+ colors[i].green =
+ colors[i].blue = (unsigned short) (65535.0 * i/(ncolors-1.0) + 0.5);
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+
+ if (!XStoreColors(p->mydisplay, mycmap, colors, ncolors)) {
+ debugr2((errout,"new_dispwin: DirectColor XStoreColors failed\n"));
+ free(colors);
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ free(colors);
+
+ myattr.colormap = mycmap;
+ attrmask |= CWColormap;
+ }
+
debugr("Opening window\n");
p->mywindow = XCreateWindow(
p->mydisplay, rootwindow,
@@ -4894,9 +5304,9 @@ int ddebug /* >0 to print debug statements to stderr */
0, /* Border width */
CopyFromParent, /* Depth */
InputOutput, /* Class */
- CopyFromParent, /* Visual */
- CWBackPixel | CWBitGravity /* Attributes Valumask */
- | CWWinGravity | CWBackingStore | CWOverrideRedirect,
+// CopyFromParent, /* Visual */
+ myvisual, /* Visual */
+ attrmask, /* Attributes Valumask */
&myattr /* Attribute details */
);
@@ -4908,10 +5318,12 @@ int ddebug /* >0 to print debug statements to stderr */
p->mydisplay, p->mywindow,
&mywattributes) == 0) {
debugr("new_dispwin: XGetWindowAttributes failed\n");
+ XFree(vinfo);
dispwin_del(p);
return NULL;
}
- p->pdepth = mywattributes.depth/3;
+ p->fdepth = mywattributes.depth/3;
+ p->rdepth = p->fdepth;
#endif
/* Setup TextProperty */
@@ -4926,6 +5338,9 @@ int ddebug /* >0 to print debug statements to stderr */
&mywmhints,
NULL); /* No class hints */
+ // ~1 should free myappname, but there doesn't seem to be
+ // a XFreeXTextProperty(&myappname); ???
+
/* Set aditional properties */
{
Atom optat;
@@ -4975,8 +5390,8 @@ int ddebug /* >0 to print debug statements to stderr */
XSelectInput(p->mydisplay,p->mywindow, ExposureMask);
+ debugr2((errout,"new_dispwin about to raise window\n"));
XMapRaised(p->mydisplay,p->mywindow);
- debug("Raised window\n");
/* ------------------------------------------------------- */
/* Suspend any screensavers if we can */
@@ -5065,7 +5480,7 @@ int ddebug /* >0 to print debug statements to stderr */
}
/* Deal with any pending events */
- debug("About to enter main loop\n");
+ debugr("About to enter main loop\n");
while(XPending(p->mydisplay) > 0) {
XNextEvent(p->mydisplay, &myevent);
switch(myevent.type) {
@@ -5079,10 +5494,94 @@ int ddebug /* >0 to print debug statements to stderr */
break;
}
}
+
+ /* Deal with Colormaps */
+ debugr2((errout,"new_dispwin: window created - dealling with colormap\n"));
+
+ if (!XGetWindowAttributes(p->mydisplay, p->mywindow, &mywa)) {
+ debugr2((errout,"new_dispwin: XGetWindowAttributes failed\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ mycmap = mywa.colormap;
+ ncolors = (1 << p->fdepth);
+
+ for (i = 0; i < 3; i++) {
+ if ((p->rmap[i] = malloc(sizeof(int) * ncolors)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed for rmap[%d]\n",i));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+ }
+
+ /* Get the X11 colormaps, so that we know how to translate */
+ /* between the frame buffer pixel value and the ramdac */
+ /* index number. */
+ if (mycmap != None) {
+ XColor *colors;
+
+ debugr2((errout,"new_dispwin: getting colormap\n"));
+
+ if ((colors = malloc(sizeof(XColor) * ncolors)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed for XColors\n"));
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ for (i = 0; i < ncolors; i++) {
+ colors[i].pixel = i << p->shift[0] | i << p->shift[1] | i << p->shift[2];
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+
+ if (!XQueryColors(p->mydisplay, mycmap, colors, ncolors)) {
+ debugr2((errout,"new_dispwin: DirectColor XQueryColors failed\n"));
+ free(colors);
+ XFree(vinfo);
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Map from frame buffer value to ramdac index */
+ for (i = 0; i < ncolors; i++) {
+ p->rmap[0][i] = (int)(colors[i].red/65535.0 * ((1 << p->rdepth)-1.0) + 0.5);
+ p->rmap[1][i] = (int)(colors[i].green/65535.0 * ((1 << p->rdepth)-1.0) + 0.5);
+ p->rmap[2][i] = (int)(colors[i].blue/65535.0 * ((1 << p->rdepth)-1.0) + 0.5);
+
+//printf("%d: %d %d %d\n",i,p->rmap[0][i],p->rmap[1][i],p->rmap[2][i]);
+ }
+
+ free(colors);
+
+ /* Assume a default linear mapping */
+ } else {
+ debugr2((errout,"new_dispwin: assuming a linear colormap\n"));
+ for (i = 0; i < ncolors; i++) {
+ p->rmap[0][i] = (int)(i/((1 << p->fdepth)-1.0) * ((1 << p->rdepth)-1.0) + 0.5);
+ p->rmap[1][i] = (int)(i/((1 << p->fdepth)-1.0) * ((1 << p->rdepth)-1.0) + 0.5);
+ p->rmap[2][i] = (int)(i/((1 << p->fdepth)-1.0) * ((1 << p->rdepth)-1.0) + 0.5);
+ }
+
+ if (p->fdepth != p->rdepth) {
+ static int warned = 0;
+ if (!warned) {
+ warning("new_dispwin: frame buffer depth %d != VideoLUT depth %d",p->fdepth, p->rdepth);
+ warned = 1;
+ }
+ }
+ }
+
+ debugr2((errout,"new_dispwin: dealt with colormap\n"));
+
} else {
/* Install the signal handler to ensure cleanup */
dispwin_install_signal_handlers(p);
}
+
+ XFree(vinfo); vinfo = NULL;
}
#endif /* UNIX X11 */
/* -------------------------------------------------- */
@@ -5750,7 +6249,7 @@ main(int argc, char *argv[]) {
if (fa < argc) {
strncpy(calname,argv[fa++],MAXNAMEL); calname[MAXNAMEL] = '\000';
if (installprofile == 0 && loadprofile == 0 && verify == 0)
- loadfile = 1; /* Load the given profile into the videoLUT */
+ loadfile = 1; /* Load the given profile into the VideoLUT */
}
#if defined(UNIX_X11)
@@ -5949,7 +6448,7 @@ main(int argc, char *argv[]) {
/* Should we load calfile instead of installed profile if it's present ??? */
if (loadprofile) {
if (calname[0] != '\000')
- warning("Profile '%s' provided as argument is being ignored!\n",calname);
+ warning("Profile '%s' provided as argument is being ignored!",calname);
/* Get the current displays profile */
debug2((errout,"Loading calibration from display profile '%s'\n",dw->name));
@@ -5974,7 +6473,7 @@ main(int argc, char *argv[]) {
is_ok_icc = 1; /* The profile is OK */
if ((wo = (icmVideoCardGamma *)icco->read_tag(icco, icSigVideoCardGammaTag)) == NULL) {
- warning("No vcgt tag found in profile - assuming linear\n");
+ warning("No vcgt tag found in profile - assuming linear");
for (i = 0; i < dw->r->nent; i++) {
iv = i/(dw->r->nent-1.0);
dw->r->v[0][i] = iv;
@@ -6008,7 +6507,7 @@ main(int argc, char *argv[]) {
} else { /* See if it's a .cal file */
int ncal;
int ii, fi, ri, gi, bi;
- double cal[3][256];
+ double cal[3][MAX_CAL_ENT];
int out_tvenc = 0; /* nz to use (16-235)/255 video encoding */
icco->del(icco); /* Don't need these now */
@@ -6032,8 +6531,8 @@ main(int argc, char *argv[]) {
if ((ncal = ccg->t[0].nsets) <= 0)
error("No data in set of file '%s'",calname);
- if (ncal != 256)
- error("Expect 256 data sets in file '%s'",calname);
+ if (ncal < 2 || ncal > MAX_CAL_ENT)
+ error("Data set size %d is out of range for '%s'",ncal,calname);
if ((fi = ccg->find_kword(ccg, 0, "DEVICE_CLASS")) < 0)
error("Calibration file '%s' doesn't contain keyword COLOR_REP",calname);
diff --git a/spectro/dispwin.h b/spectro/dispwin.h
index b5e14ce..47fd256 100644
--- a/spectro/dispwin.h
+++ b/spectro/dispwin.h
@@ -73,11 +73,11 @@ WINSHLWAPI LPWSTR WINAPI PathFindFileNameW(LPCWSTR);
#endif /* NT */
-#ifdef __APPLE__ /* Assume OS X Cocoa */
+#ifdef UNIX_APPLE /* Assume OS X Cocoa */
#include <Carbon/Carbon.h> /* To declare CGDirectDisplayID */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
#include <X11/Xlib.h>
@@ -114,9 +114,9 @@ typedef struct {
char monid[128]; /* Monitor ID */
int prim; /* NZ if primary display monitor */
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
CGDirectDisplayID ddid;
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
int screen; /* Screen to select */
int uscreen; /* Underlying screen */
@@ -158,9 +158,17 @@ struct _ramdac {
/* Should have separate frame buffer depth + representation to account */
/* for floating point frame buffers, even though this isn't currently used. */
- int pdepth; /* Frame buffer depth into RAMDAC, usually 8 */
- int nent; /* Number of entries, = 2^pdepth */
- double *v[3]; /* 2^pdepth entries for RGB, values 0.0 - 1.0 */
+ int fdepth; /* Frame buffer depth, typically 8, could be more. */
+ int rdepth; /* Expected ramdac index depth. May be different to fdepth */
+ /* if there is another level of mapping between the frame buffer */
+ /* and ramdac, i.e. X11 DirectorColor Colormap. */
+
+ int ndepth; /* Actual ramdac depth, typically = rdepth */
+ int nent; /* Number of entries, = 2^ndepth, typically = 2^rdepth, */
+ /* but may be different for some video cards. */
+ /* Will be 0 if ramdac is not accessible */
+
+ double *v[3]; /* nent entries for RGB, values 0.0 - 1.0 */
/* Clone ourselves */
struct _ramdac *(*clone)(struct _ramdac *p);
@@ -255,12 +263,12 @@ struct _dispwin {
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
CGDirectDisplayID ddid;
void *osx_cntx; /* OSX specific info */
int btf; /* Flag, nz if window has been brought to the front once */
int winclose; /* Flag, set to nz if window was closed */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
Display *mydisplay;
@@ -271,6 +279,9 @@ struct _dispwin {
unsigned char *edid; /* 128 or 256 bytes of monitor EDID, NULL if none */
int edid_len; /* 128 or 256 */
+ int shift[3]; /* Bit shift to create RGB value from components */
+ int *rmap[3]; /* Map of fdepth to rdepth values */
+
#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2
/* Xrandr stuff - output is connected 1:1 to a display */
RRCrtc crtc; /* Associated crtc */
@@ -308,10 +319,21 @@ struct _dispwin {
volatile int cberror; /* NZ if error detected in a callback routine */
int ddebug; /* >0 to print debug to stderr */
+ int warned; /* Warning message has been issued */
+
/* public: */
- int pdepth; /* Frame buffer plane depth of display */
- int edepth; /* Notional ramdac entry size in bits. (Bits actually used may be less) */
- /* This is used to scale out_tvenc appropriately */
+ int fdepth; /* Frame buffer depth, typically 8, could be more */
+ int rdepth; /* Expected ramdac index depth. May be different to fdepth */
+ /* if there is another level of mapping between the frame buffer */
+ /* and ramdac, i.e. X11 DirectorColor Colormap. */
+
+ int ndepth; /* Actual ramdac depth, typically = rdepth */
+ int nent; /* Number of entries, = s^ndepth, typically = 2^rdepth, */
+ /* but may be different for some video cards. */
+ /* Will be 0 if ramdac is not accessible */
+
+ int edepth; /* Notional frame buffer/ramdac entry size in bits. (Bits actually used */
+ /* may be less). This is just used to scale out_tvenc appropriately. */
/* Get RAMDAC values. ->del() when finished. */
/* Return NULL if not possible */
diff --git a/spectro/dtp20.c b/spectro/dtp20.c
index 6af2484..a125a53 100644
--- a/spectro/dtp20.c
+++ b/spectro/dtp20.c
@@ -72,6 +72,7 @@
#include "conv.h"
#include "icoms.h"
#include "dtp20.h"
+#include "xrga.h"
static inst_code dtp20_interp_code(inst *pp, int ec);
static inst_code activate_mode(dtp20 *p);
@@ -345,12 +346,27 @@ dtp20_init_inst(inst *pp) {
dtp20 *p = (dtp20 *)pp;
char buf[MAX_MES_SIZE];
inst_code rv = inst_ok;
+ char *envv;
a1logd(p->log, 2, "dtp20_init_inst: called\n");
if (p->gotcoms == 0)
return inst_no_coms; /* Must establish coms before calling init */
+
+ p->native_calstd = xcalstd_xrdi;
+ p->target_calstd = xcalstd_native; /* Default to native calibration standard*/
+
+ /* Honour Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ p->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ p->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ p->target_calstd = xcalstd_gmdi;
+ }
+
/* Reset it (without disconnecting USB or clearing stored data) */
if ((rv = dtp20_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
return rv;
@@ -534,7 +550,8 @@ ipatch *vals) { /* Pointer to array of values */
tp += strlen(tp) + 1;
}
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
/* Gather the results in Spectral reflectance */
if ((ev = dtp20_command(p, "0318CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
@@ -575,6 +592,11 @@ ipatch *vals) { /* Pointer to array of values */
}
a1logv(p->log, 1, "All saved strips read\n");
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, npatch, xcalstd_nonpol, p->target_calstd, p->native_calstd,
+ instClamp);
+
return inst_ok;
}
@@ -762,7 +784,8 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
}
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
/* Gather the results in Spectral reflectance */
if ((ev = dtp20_command(p, "0318CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
@@ -813,6 +836,11 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
}
}
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, npatch, xcalstd_nonpol, p->target_calstd, p->native_calstd,
+ instClamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -993,7 +1021,8 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
val->duration = 0.0;
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
int j;
/* Set to read spectral reflectance */
@@ -1051,6 +1080,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
}
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(val, 1, xcalstd_nonpol, p->target_calstd, p->native_calstd, clamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -1086,6 +1118,7 @@ static inst_code dtp20_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
dtp20 *p = (dtp20 *)pp;
@@ -1098,6 +1131,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = dtp20_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -1136,6 +1170,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
;
*cp = '\000';
strcpy(id, buf);
+ *idtype = inst_calc_id_ref_sn;
*calc = inst_calc_man_ref_white;
return inst_cal_setup;
}
@@ -1686,7 +1721,7 @@ inst_opt_type m, /* Requested status type */
}
/* !! It's not clear if there is a way of knowing */
- /* whether the instrument has a UV filter. */
+ /* whether the instrument has a UV filter !! */
/* Use default implementation of other inst_opt_type's */
{
diff --git a/spectro/dtp20.h b/spectro/dtp20.h
index c575c67..a8b6862 100644
--- a/spectro/dtp20.h
+++ b/spectro/dtp20.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define DTP20_INTERNAL_ERROR 0x81 /* Internal software error */
#define DTP20_COMS_FAIL 0x82 /* Communication failure */
@@ -128,12 +132,17 @@ struct _dtp20 {
int savix; /* Index of last saved spot reading read */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
}; typedef struct _dtp20 dtp20;
/* Constructor */
extern dtp20 *new_dtp20(icoms *icom, instType itype);
-
+#ifdef __cplusplus
+ }
+#endif
#define DTP20_H
#endif /* DTP20_H */
diff --git a/spectro/dtp22.c b/spectro/dtp22.c
index 2cb3634..37249f0 100644
--- a/spectro/dtp22.c
+++ b/spectro/dtp22.c
@@ -32,6 +32,11 @@
and agreed to support.
*/
+/*
+ Would like to add a thread to return status of
+ switch, so that we can fully run this in progromatic trigger mode.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -51,6 +56,7 @@
#include "conv.h"
#include "icoms.h"
#include "dtp22.h"
+#include "xrga.h"
/* Default flow control (Instrument doesn't support HW flow control) */
#define DEFFC fc_XonXOff
@@ -186,7 +192,7 @@ dtp22_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
} else if (fc == fc_Hardware) {
fcc = "0104CF\r";
} else {
- fc = fc_none;
+ fc = fc_None;
fcc = "0004CF\r";
}
@@ -209,40 +215,37 @@ dtp22_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* The tick to give up on */
etime = msec_time() + (long)(1000.0 * tout + 0.5);
- while (msec_time() < etime) {
- a1logd(p->log, 4, "dtp22_init_coms: Trying different baud rates (%u msec to go)\n",
- etime - msec_time());
-
- /* Until we time out, find the correct baud rate */
- for (i = ci; msec_time() < etime;) {
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+
+ a1logd(p->log, 4, "dtp22_init_coms: Trying %s baud, %d msec to go\n",
+ baud_rate_to_str(brt[i]), etime- msec_time());
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
- a1logd(p->log, 1, "dtp22_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
- return dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
- }
- if (((ev = dtp22_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
- != inst_coms_fail)
- break; /* We've got coms */
-
- /* Check for user abort */
- if (p->uicallback != NULL) {
- inst_code ev;
- if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
- a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
- return ev;
- }
+ if ((se = p->icom->set_ser_port(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp22_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
+ }
+ if (((ev = dtp22_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail)
+ goto got_coms; /* We've got coms or user abort */
+
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
+ return ev;
}
- if (++i >= 5)
- i = 0;
}
- break; /* Got coms */
+ if (++i >= 5)
+ i = 0;
}
+ /* We haven't established comms */
+ return inst_coms_fail;
- if (msec_time() >= etime) { /* We haven't established comms */
- return inst_coms_fail;
- }
+ got_coms:;
/* Set the handshaking */
if ((ev = dtp22_command(p, fcc, buf, MAX_MES_SIZE, 0.2)) != inst_ok)
@@ -287,6 +290,7 @@ dtp22_init_inst(inst *pp) {
dtp22 *p = (dtp22 *)pp;
char buf[MAX_MES_SIZE], *bp;
inst_code ev = inst_ok;
+ char *envv;
int i;
a1logd(p->log, 2, "dtp22_init_inst: called\n");
@@ -294,6 +298,19 @@ dtp22_init_inst(inst *pp) {
if (p->gotcoms == 0)
return inst_internal_error; /* Must establish coms before calling init */
+ p->native_calstd = xcalstd_xrdi;
+ p->target_calstd = xcalstd_native; /* Default to native calibration standard*/
+
+ /* Honour Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ p->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ p->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ p->target_calstd = xcalstd_gmdi;
+ }
+
/* Warm reset it */
if ((ev = dtp22_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
return ev;
@@ -333,7 +350,7 @@ dtp22_init_inst(inst *pp) {
/* - - - - - - - - - - - - - - - - - - - - - - - - */
/* Get some information about the instrument */
- if ((ev = dtp22_command(p, "GI\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok) {
+ if ((ev = dtp22_command(p, "GI\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok) {
a1logd(p->log, 1, "dtp22: GI command failed with ICOM err 0x%x\n",ev);
return ev;
}
@@ -577,7 +594,8 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
val->sp.spec_n = 0;
val->duration = 0.0;
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
int j;
char *fmt;
@@ -605,6 +623,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
val->sp.norm = 100.0;
}
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(val, 1, xcalstd_nonpol, p->target_calstd, p->native_calstd, clamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -640,6 +661,7 @@ inst_code dtp22_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
dtp22 *p = (dtp22 *)pp;
@@ -654,6 +676,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = dtp22_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -683,7 +706,8 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (*calt & inst_calt_ref_white) { /* White calibration */
- sprintf(id, "Serial no. %d",p->plaqueno);
+ *idtype = inst_calc_id_ref_sn;
+ sprintf(id, "%d",p->plaqueno);
if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_whitek) {
*calc = inst_calc_man_ref_whitek;
ev = inst_cal_setup;
@@ -1046,6 +1070,37 @@ dtp22_get_set_opt(inst *pp, inst_opt_type m, ...)
{
dtp22 *p = (dtp22 *)pp;
+ /* Set xcalstd */
+ if (m == inst_opt_set_xcalstd) {
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ p->target_calstd = standard;
+
+ return inst_ok;
+ }
+
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (p->target_calstd == xcalstd_native)
+ *standard = p->native_calstd; /* If not overridden */
+ else
+ *standard = p->target_calstd; /* Overidden std. */
+
+ return inst_ok;
+ }
+
/* Record the trigger mode */
if (m == inst_opt_trig_prog
|| m == inst_opt_trig_user
@@ -1054,7 +1109,17 @@ dtp22_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- return inst_unsupported;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/dtp22.h b/spectro/dtp22.h
index 95dce16..af565e8 100644
--- a/spectro/dtp22.h
+++ b/spectro/dtp22.h
@@ -35,6 +35,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update dtp22_interp_error() and dtp22_interp_code() in dtp22.c */
/* if anything of these #defines are added or subtracted */
@@ -95,11 +99,17 @@ struct _dtp22 {
int noutocalib; /* Don't mode change or auto calibrate */
inst_opt_type trig; /* Reading trigger mode */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
}; typedef struct _dtp22 dtp22;
/* Constructor */
extern dtp22 *new_dtp22(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define DTP22_H
#endif /* DTP22_H */
diff --git a/spectro/dtp41.c b/spectro/dtp41.c
index 44ac6c6..97a3db1 100644
--- a/spectro/dtp41.c
+++ b/spectro/dtp41.c
@@ -53,6 +53,7 @@
#include "conv.h"
#include "icoms.h"
#include "dtp41.h"
+#include "xrga.h"
/* Default flow control */
#define DEFFC fc_XonXOff
@@ -169,7 +170,7 @@ dtp41_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
} else if (fc == fc_Hardware) {
fcc = "0104CF\r";
} else {
- fc = fc_none;
+ fc = fc_None;
fcc = "0004CF\r";
}
@@ -192,36 +193,35 @@ dtp41_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* The tick to give up on */
etime = msec_time() + (long)(1000.0 * tout + 0.5);
- while (msec_time() < etime) {
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ a1logd(p->log, 4, "dtp41_init_coms: Trying %s baud, %d msec to go\n",
+ baud_rate_to_str(brt[i]), etime- msec_time());
+ if ((se = p->icom->set_ser_port(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp41_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp41_interp_code((inst *)p, icoms2dtp41_err(se));
+ }
+ if (((ev = dtp41_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail)
+ goto got_coms; /* We've got coms or user abort */
- /* Until we time out, find the correct baud rate */
- for (i = ci; msec_time() < etime;) {
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
- a1logd(p->log, 1, "dtp41_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
- return dtp41_interp_code((inst *)p, icoms2dtp41_err(se));
- }
- if (((ev = dtp41_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
- != inst_coms_fail)
- break; /* We've got coms */
-
- /* Check for user abort */
- if (p->uicallback != NULL) {
- inst_code ev;
- if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
- a1logd(p->log, 1, "dtp41_init_coms: user aborted\n");
- return inst_user_abort;
- }
+
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "dtp41_init_coms: user aborted\n");
+ return inst_user_abort;
}
- if (++i >= 9)
- i = 0;
}
- break; /* Got coms */
+ if (++i >= 9)
+ i = 0;
}
+ /* We haven't established comms */
+ return inst_coms_fail;
- if (msec_time() >= etime) { /* We haven't established comms */
- return inst_coms_fail;
- }
+ got_coms:;
/* set the protocol to RCI */
if ((ev = dtp41_command(p, "0012CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
@@ -319,6 +319,7 @@ static inst_code
dtp41_init_inst(inst *pp) {
dtp41 *p = (dtp41 *)pp;
static char tbuf[100], buf[MAX_MES_SIZE];
+ char *envv;
inst_code ev = inst_ok;
a1logd(p->log, 2, "dtp41_init_inst: called\n");
@@ -326,6 +327,19 @@ dtp41_init_inst(inst *pp) {
if (p->gotcoms == 0)
return inst_internal_error; /* Must establish coms before calling init */
+ p->native_calstd = xcalstd_xrdi;
+ p->target_calstd = xcalstd_native; /* Default to native calibration standard*/
+
+ /* Honour Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ p->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ p->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ p->target_calstd = xcalstd_gmdi;
+ }
+
/* Resetting instrument resets the baud rate, so do manual reset. */
/* Set emulation mode to DTP41 */
@@ -603,7 +617,9 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
tp += strlen(tp) + 1;
}
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || (XCALSTD_NEEDED(p->target_calstd, p->native_calstd)
+ && ((p->mode & inst_mode_illum_mask) != inst_mode_transmission))) {
/* Gather the results in Spectral reflectance */
if ((ev = dtp41_command(p, "0403TS\r", buf, MAX_RD_SIZE, 0.5 + npatch * 0.1)) != inst_ok)
@@ -639,6 +655,11 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
tp += strlen(tp) + 1;
}
}
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, npatch, xcalstd_nonpol, p->target_calstd, p->native_calstd,
+ instClamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -790,7 +811,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
val->sp.spec_n = 0;
val->duration = 0.0;
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || (XCALSTD_NEEDED(p->target_calstd, p->native_calstd)
+ && ((p->mode & inst_mode_illum_mask) != inst_mode_transmission))) {
int j;
/* Gather the results in Spectral reflectance */
@@ -840,6 +863,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if ((ev = dtp41_command(p, "0113CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
return ev;
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(val, 1, xcalstd_nonpol, p->target_calstd, p->native_calstd, clamp);
+
if (user_trig)
return inst_user_trig;
return inst_ok;
@@ -881,6 +907,7 @@ inst_code dtp41_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
dtp41 *p = (dtp41 *)pp;
@@ -892,6 +919,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = dtp41_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -919,7 +947,6 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
return inst_unsupported;
}
-
if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
if (*calt & inst_calt_trans_white) {
@@ -1236,6 +1263,37 @@ dtp41_get_set_opt(inst *pp, inst_opt_type m, ...)
inst_code rv = inst_ok;
static char buf[MAX_MES_SIZE];
+ /* Set xcalstd */
+ if (m == inst_opt_set_xcalstd) {
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ p->target_calstd = standard;
+
+ return inst_ok;
+ }
+
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (p->target_calstd == xcalstd_native)
+ *standard = p->native_calstd; /* If not overridden */
+ else
+ *standard = p->target_calstd; /* Overidden std. */
+
+ return inst_ok;
+ }
+
if (!p->gotcoms)
return inst_no_coms;
if (!p->inited)
@@ -1259,7 +1317,17 @@ dtp41_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- return inst_unsupported;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/dtp41.h b/spectro/dtp41.h
index 529f94c..018ed5c 100644
--- a/spectro/dtp41.h
+++ b/spectro/dtp41.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define DTP41_INTERNAL_ERROR 0x61 /* Internal software error */
#define DTP41_COMS_FAIL 0x62 /* Communication failure */
@@ -101,10 +105,17 @@ struct _dtp41 {
int need_cal; /* needs calibration */
inst_opt_type trig; /* Reading trigger mode */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
}; typedef struct _dtp41 dtp41;
/* Constructor */
extern dtp41 *new_dtp41(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
+
#define DTP41_H
#endif /* DTP41_H */
diff --git a/spectro/dtp51.c b/spectro/dtp51.c
index ab1999d..0b2ecab 100644
--- a/spectro/dtp51.c
+++ b/spectro/dtp51.c
@@ -202,7 +202,7 @@ dtp51_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
} else if (fc == fc_Hardware) {
fcc = "0104CF\r";
} else {
- fc = fc_none;
+ fc = fc_None;
fcc = "0004CF\r";
}
@@ -225,37 +225,36 @@ dtp51_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* The tick to give up on */
etime = msec_time() + (long)(1000.0 * tout + 0.5);
- while (msec_time() < etime) {
-
- /* Until we time out, find the correct baud rate */
- for (i = ci; msec_time() < etime;) {
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
- a1logd(p->log, 1, "dtp51_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
- return dtp51_interp_code((inst *)p, icoms2dtp51_err(se));
- }
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ a1logd(p->log, 4, "dtp51_init_coms: Trying %s baud, %d msec to go\n",
+ baud_rate_to_str(brt[i]), etime- msec_time());
+ if ((se = p->icom->set_ser_port(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp51_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp51_interp_code((inst *)p, icoms2dtp51_err(se));
+ }
- if (((ev = dtp51_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
- != inst_coms_fail)
- break; /* We've got coms */
+ if (((ev = dtp51_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail)
+ goto got_coms; /* We've got coms or user abort */
- /* Check for user abort */
- if (p->uicallback != NULL) {
- inst_code ev;
- if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
- a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
- return inst_user_abort;
- }
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
+ return inst_user_abort;
}
- if (++i >= 5)
- i = 0;
}
- break; /* Got coms */
+ if (++i >= 5)
+ i = 0;
}
- if (msec_time() >= etime) { /* We haven't established comms */
- return inst_coms_fail;
- }
+ /* We haven't established comms */
+ return inst_coms_fail;
+
+ got_coms:;
/* Set the handshaking */
if ((ev = dtp51_command(p, fcc, buf, MAX_MES_SIZE, 1.5)) != inst_ok)
@@ -595,6 +594,7 @@ inst_code dtp51_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
dtp51 *p = (dtp51 *)pp;
@@ -606,6 +606,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = dtp51_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -857,8 +858,7 @@ inst_code dtp51_set_mode(inst *pp, inst_mode m) {
* was assume that all of these can be done before initialisation.
*/
static inst_code
-dtp51_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+dtp51_get_set_opt(inst *pp, inst_opt_type m, ...) {
dtp51 *p = (dtp51 *)pp;
static char buf[MAX_MES_SIZE];
@@ -868,7 +868,31 @@ dtp51_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- return inst_unsupported;
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ *standard = p->native_calstd;
+
+ return inst_ok;
+ }
+
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
@@ -896,5 +920,7 @@ extern dtp51 *new_dtp51(icoms *icom, instType itype) {
p->icom = icom;
p->itype = itype;
+ p->native_calstd = xcalstd_xrdi; /* Not alterable */
+
return p;
}
diff --git a/spectro/dtp51.h b/spectro/dtp51.h
index 329c5d6..804b8ae 100644
--- a/spectro/dtp51.h
+++ b/spectro/dtp51.h
@@ -35,6 +35,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define DTP51_INTERNAL_ERROR 0x61 /* Internal software error */
#define DTP51_COMS_FAIL 0x62 /* Communication failure */
@@ -91,12 +95,16 @@ struct _dtp51 {
int need_cal; /* needs calibration */
inst_opt_type trig; /* Reading trigger mode */
- }; typedef struct _dtp51 dtp51;
+ xcalstd native_calstd; /* Instrument native calibration standard */
+
+}; typedef struct _dtp51 dtp51;
/* Constructor */
extern dtp51 *new_dtp51(icoms *icom, instType itype);
-
+#ifdef __cplusplus
+ }
+#endif
#define DTP51_H
#endif /* DTP51_H */
diff --git a/spectro/dtp92.c b/spectro/dtp92.c
index 3b6dacd..33b8fa0 100644
--- a/spectro/dtp92.c
+++ b/spectro/dtp92.c
@@ -58,7 +58,7 @@
#include "dtp92.h"
/* Default flow control */
-#define DEFFC fc_none
+#define DEFFC fc_None
#define DEF_TIMEOUT 0.5
#define MED_TIMEOUT 2.5
@@ -147,7 +147,8 @@ dtp92_fcommand(
icoms_fix(in), icoms_fix(out),rv);
#ifdef IGNORE_NEEDS_OFFSET_DRIFT_CAL_ERR
- if (strcmp(in, "0PR\r") == 0 && rv == DTP92_NEEDS_OFFSET_DRIFT_CAL) {
+ if ((strcmp(in, "0PR\r") == 0
+ || strcmp(in, "EFC\r") == 0) && rv == DTP92_NEEDS_OFFSET_DRIFT_CAL) {
static int warned = 0;
if (!warned) {
a1logw(p->log,"dtp92: Got error NEEDS_OFFSET_DRIFT_CAL on instrument reset - being ignored.");
@@ -239,7 +240,7 @@ dtp92_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
} else if (fc == fc_Hardware) {
fcc = "0104CF\r";
} else {
- fc = fc_none;
+ fc = fc_None;
fcc = "0004CF\r";
}
@@ -262,41 +263,42 @@ dtp92_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* The tick to give up on */
etime = msec_time() + (long)(1000.0 * tout + 0.5);
- while (msec_time() < etime) {
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ a1logd(p->log, 4, "dtp92_init_coms: Trying %s baud, %d msec to go\n",
+ baud_rate_to_str(brt[i]), etime- msec_time());
+ if ((se = p->icom->set_ser_port(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp92_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp92_interp_code((inst *)p, icoms2dtp92_err(se));
+ }
- a1logd(p->log, 4, "dtp92_init_coms: Trying different baud rates (%u msec to go)\n",
- etime - msec_time());
+ /* Throw one response away, to work around some USB<->Serial quirks */
+ p->icom->write_read(p->icom, "\r", 0, buf, MAX_MES_SIZE, NULL, ">", 1, 0.1);
- /* Until we time out, find the correct baud rate */
- for (i = ci; msec_time() < etime;) {
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
- a1logd(p->log, 1, "dtp92_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
- return dtp92_interp_code((inst *)p, icoms2dtp92_err(se));
- }
+ if (((ev = dtp92_command(p, "\r", buf, MAX_MES_SIZE, DEF_TIMEOUT)) & inst_mask)
+ != inst_coms_fail)
+ goto got_coms; /* We've got coms or user abort */
- if (((ev = dtp92_command(p, "\r", buf, MAX_MES_SIZE, DEF_TIMEOUT)) & inst_mask)
- != inst_coms_fail)
- break; /* We've got coms or user abort */
-
- /* Check for user abort */
- if (p->uicallback != NULL) {
- inst_code ev;
- if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
- a1logd(p->log, 1, "dtp92_init_coms: user aborted\n");
- return inst_user_abort;
- }
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "dtp92_init_coms: user aborted\n");
+ return inst_user_abort;
}
-
- if (++i >= 5)
- i = 0;
}
- break; /* Got coms */
- }
- if (msec_time() >= etime) { /* We haven't established comms */
- return inst_coms_fail;
+ if (++i >= 5)
+ i = 0;
}
+ /* We haven't established comms */
+ return inst_coms_fail;
+
+ got_coms:;
+
+ /* Throw one response away, to work around some USB<->Serial quirks */
+ p->icom->write_read(p->icom, "\r", 0, buf, MAX_MES_SIZE, NULL, ">", 1, 0.1);
/* Set the handshaking */
if ((ev = dtp92_command(p, fcc, buf, MAX_MES_SIZE, DEF_TIMEOUT)) != inst_ok)
@@ -317,6 +319,7 @@ dtp92_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Loose a character (not sure why) */
p->icom->write_read(p->icom, "\r", 0, buf, MAX_MES_SIZE, NULL, ">", 1, 0.1);
+
#else /* !ENABLE_SERIAL */
a1logd(p->log, 1, "dtp92: Failed to find serial connection to instrument\n");
return inst_coms_fail;
@@ -621,6 +624,14 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if (sscanf(buf, " X%*c %lf\t Y%*c %lf\t Z%*c %lf ",
&val->XYZ[0], &val->XYZ[1], &val->XYZ[2]) == 3) {
+ /* Hmm. The DTP92 seems to return strange X & Z values if the light */
+ /* level is zero, and it's black level is out of calibration */
+ /* (i.e. internally it has -ve Y ?) */
+ if (val->XYZ[1] == 0.0 && val->XYZ[0] == 999.99)
+ val->XYZ[0] = 0.0;
+ if (val->XYZ[1] == 0.0 && val->XYZ[2] == 999.99)
+ val->XYZ[2] = 0.0;
+
/* Apply the colorimeter correction matrix */
icmMulBy3x3(val->XYZ, p->ccmat, val->XYZ);
@@ -778,6 +789,7 @@ static inst_code dtp92_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
dtp92 *p = (dtp92 *)pp;
@@ -790,6 +802,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = dtp92_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -1356,8 +1369,7 @@ int *cbid) {
* error if it hasn't been initialised.
*/
static inst_code
-dtp92_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+dtp92_get_set_opt(inst *pp, inst_opt_type m, ...) {
dtp92 *p = (dtp92 *)pp;
char buf[MAX_MES_SIZE];
inst_code ev = inst_ok;
@@ -1369,12 +1381,17 @@ dtp92_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- if (!p->gotcoms)
- return inst_no_coms;
- if (!p->inited)
- return inst_no_init;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
- return inst_unsupported;
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/dtp92.h b/spectro/dtp92.h
index 317fb7a..8a6885e 100644
--- a/spectro/dtp92.h
+++ b/spectro/dtp92.h
@@ -35,6 +35,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update dtp92_interp_error() and dtp92_interp_code() in dtp92.c */
/* if anything of these #defines are added or subtracted */
@@ -100,6 +104,9 @@ struct _dtp92 {
/* Constructor */
extern dtp92 *new_dtp92(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define DTP92_H
#endif /* DTP92_H */
diff --git a/spectro/ex1.c b/spectro/ex1.c
index b336cbc..5f4eae2 100644
--- a/spectro/ex1.c
+++ b/spectro/ex1.c
@@ -328,7 +328,9 @@ ex1_init_inst(inst *pp) {
//printf("~1 raw range = %d - %d\n",sconf->rawrange.off, sconf->rawrange.off + sconf->rawrange.num-1);
//printf("~1 = %f - %f nm\n",rspec_raw2nm(sconf, sconf->rawrange.off), rspec_raw2nm(sconf, sconf->rawrange.off + sconf->rawrange.num-1));
- sconf->ktype = rspec_gausian;
+ sconf->ktype = rspec_gausian; /* Default */
+// sconf->ktype = rspec_lanczos2;
+// sconf->ktype = rspec_lanczos3;
// sconf->ktype = rspec_triangle;
// sconf->ktype = rspec_cubicspline;
sconf->wl_space = 2.0;
@@ -702,6 +704,7 @@ inst_code ex1_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
ex1 *p = (ex1 *)pp;
@@ -1160,8 +1163,7 @@ static void ex1_set_noinitcalib(ex1 *p, int v, int losecs) {
* error if it hasn't been initialised.
*/
static inst_code
-ex1_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+ex1_get_set_opt(inst *pp, inst_opt_type m, ...) {
ex1 *p = (ex1 *)pp;
inst_code ev = inst_ok;
@@ -1194,7 +1196,17 @@ ex1_get_set_opt(inst *pp, inst_opt_type m, ...)
if (!p->inited)
return inst_no_init;
- return inst_unsupported;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/ex1.h b/spectro/ex1.h
index d69b7ca..a278777 100644
--- a/spectro/ex1.h
+++ b/spectro/ex1.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Communication errors */
#define EX1_TIMEOUT 0xFF02 /* Communication timeout */
#define EX1_COMS_FAIL 0xFF03 /* Communication failure */
@@ -143,6 +147,9 @@ struct _ex1 {
/* Constructor */
extern ex1 *new_ex1(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define EX1_H
#endif /* EX1_H */
diff --git a/spectro/hcfr.c b/spectro/hcfr.c
index a6c457e..22b5170 100644
--- a/spectro/hcfr.c
+++ b/spectro/hcfr.c
@@ -366,7 +366,7 @@ hcfr_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
inst_code ev = inst_ok;
icomuflags usbflags = icomuf_no_open_clear | icomuf_detach;
-#if defined(__APPLE__) && !defined(__ppc__)
+#if defined(UNIX_APPLE) && !defined(__ppc__)
/* Except on Intel OS X 10.4/5 for some reasone. */
/* It would be good if the HCFR had a better USB implementation... */
usbflags &= ~icomuf_no_open_clear;
@@ -919,7 +919,17 @@ hcfr_get_set_opt(inst *pp, inst_opt_type m, ...) {
return inst_ok;
}
- return inst_unsupported;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/hcfr.h b/spectro/hcfr.h
index 8910cec..2420fdf 100644
--- a/spectro/hcfr.h
+++ b/spectro/hcfr.h
@@ -35,11 +35,14 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Required minimum firmware version */
#define HCFR_FIRMWARE_MAJOR_VERSION 5
#define HCFR_FIRMWARE_MINOR_VERSION 0
-
/* Command byte contents. (A value of 0x00 won't be tranmsitted properly) */
/* 0xff = get firmware version */
@@ -99,6 +102,9 @@ struct _hcfr {
/* Constructor */
extern hcfr *new_hcfr(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define HCFR_H
#endif /* HCFR_H */
diff --git a/spectro/hidio.c b/spectro/hidio.c
index c930755..2d8649f 100644
--- a/spectro/hidio.c
+++ b/spectro/hidio.c
@@ -178,7 +178,7 @@ int hid_get_paths(icompaths *p) {
pdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
dinfod.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; ; i++) {
- instType itype;
+ devType itype;
if (SetupDiEnumDeviceInterfaces(hdinfo, NULL, &HidGuid, i, &did) == 0) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
@@ -269,7 +269,7 @@ int hid_get_paths(icompaths *p) {
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
CFAllocatorContext alocctx;
@@ -308,7 +308,7 @@ int hid_get_paths(icompaths *p) {
CFNumberRef vref, pref; /* HID Vendor and Product ID propeties */
CFNumberRef lidpref; /* Location ID properties */
unsigned int vid = 0, pid = 0, lid = 0;
- instType itype;
+ devType itype;
IOHIDDeviceRef ioob = values[i]; /* HID object found */
if ((vref = IOHIDDeviceGetProperty(ioob, CFSTR(kIOHIDVendorIDKey))) != NULL) {
@@ -376,7 +376,7 @@ int hid_get_paths(icompaths *p) {
CFNumberRef vref, pref; /* HID Vendor and Product ID propeties */
CFNumberRef lidpref; /* Location ID properties */
unsigned int vid = 0, pid = 0, lid = 0;
- instType itype;
+ devType itype;
if ((ioob = IOIteratorNext(mit)) == 0)
break;
@@ -426,7 +426,7 @@ int hid_get_paths(icompaths *p) {
IOObjectRelease(mit); /* Release the itterator */
}
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
@@ -483,14 +483,14 @@ int hid_get_paths(icompaths *p) {
#endif /* NEVER */
#endif /* UNIX_X11 */
- a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
return ICOM_OK;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* HID Interrupt callback for OS X */
/* This seems to only get called when the run loop is active. */
@@ -516,7 +516,7 @@ UInt32 size
a1logd(p->log, 8, "HID callback has no run loop\n");
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -571,7 +571,7 @@ char **pnames /* List of process names to try and kill before opening */
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
/* Open the device */
@@ -644,7 +644,7 @@ char **pnames /* List of process names to try and kill before opening */
}
}
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
p->is_open = 1;
a1logd(p->log, 8, "hid_open_port: HID port is now open\n");
@@ -669,7 +669,7 @@ void hid_close_port(icoms *p) {
CloseHandle(p->hidd->fh);
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
if (IOHIDDeviceClose(p->hidd->ioob, kIOHIDOptionsTypeNone) != kIOReturnSuccess) {
a1loge(p->log, ICOM_SYS, "hid_close_port: closing HID port '%s' failed",p->name);
@@ -701,7 +701,7 @@ void hid_close_port(icoms *p) {
}
p->hidd->device = NULL;
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
p->is_open = 0;
a1logd(p->log, 8, "hid_close_port: has been released and closed\n");
@@ -770,7 +770,7 @@ icoms_hid_read(icoms *p,
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
IOReturn result;
@@ -899,7 +899,7 @@ printf("~1 IOHIDDeviceGet returned 0x%x\n",result);
}
#endif // NEVER
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
if (breadp != NULL)
*breadp = bread;
@@ -968,7 +968,7 @@ icoms_hid_write(icoms *p,
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
{
IOReturn result;
@@ -1039,7 +1039,7 @@ printf("~1 IOHIDDeviceSetReportWithCallback returned 0x%x\n",result);
}
}
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
if (bwrittenp != NULL)
*bwrittenp = bwritten;
@@ -1101,7 +1101,7 @@ int hid_copy_hid_idevice(icoms *d, icompath *s) {
return ICOM_SYS;
}
#endif
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
d->hidd->ioob = s->hidd->ioob;
CFRetain(d->hidd->ioob);
@@ -1109,7 +1109,7 @@ int hid_copy_hid_idevice(icoms *d, icompath *s) {
d->hidd->ioob = s->hidd->ioob;
IOObjectRetain(d->hidd->ioob);
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined (UNIX_X11)
#endif
return ICOM_OK;
@@ -1124,7 +1124,7 @@ void hid_del_hid_idevice(struct hid_idevice *hidd) {
if (hidd->dpath != NULL)
free(hidd->dpath);
#endif
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
if (hidd->ioob != 0)
CFRelease(hidd->ioob);
@@ -1132,7 +1132,7 @@ void hid_del_hid_idevice(struct hid_idevice *hidd) {
if (hidd->ioob != 0)
IOObjectRelease(hidd->ioob);
#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined (UNIX_X11)
#endif
free(hidd);
diff --git a/spectro/hidio.h b/spectro/hidio.h
index 90a741b..87edd43 100644
--- a/spectro/hidio.h
+++ b/spectro/hidio.h
@@ -1,7 +1,7 @@
#ifndef HIDIO_H
- /* General USB HID I/O support */
+/* General USB HID I/O support */
/*
* Argyll Color Correction System
@@ -16,16 +16,17 @@
* see the License2.txt file for licencing details.
*/
+
/* These routines supliement the class code in ntio.c and unixio.c */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
#include <sys/param.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <CoreFoundation/CoreFoundation.h>
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#ifdef __cplusplus
extern "C" {
@@ -59,7 +60,7 @@ struct hid_idevice {
HANDLE fh; /* File handle for write/read */
OVERLAPPED ols; /* Overlapped structure for write/read */
#endif
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
# if defined(USE_NEW_OSX_CODE) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
int lid; /* Location ID */
IOHIDDeviceRef ioob; /* Object to open */
diff --git a/spectro/huey.c b/spectro/huey.c
index b09ed2c..2c82b4c 100644
--- a/spectro/huey.c
+++ b/spectro/huey.c
@@ -885,7 +885,8 @@ huey_check_unlock(
if ((ev = huey_command(p, i1d_status, buf, buf, 1.0,1.0)) != inst_ok)
return ev;
- if (strncmp((char *)buf, "Locked", 6) == 0) {
+ /* Hmm. Some Lenovo Huey's say they are unlocked, even when they are not. */
+ if (p->lenovo || strncmp((char *)buf, "Locked", 6) == 0) {
memset(buf, 0, 7);
if (p->lenovo)
strcpy((char *)buf,"huyL");
@@ -902,6 +903,7 @@ huey_check_unlock(
if (strncmp((char *)buf, "huL002", 6) != 0 /* Lenovo Huey ? */
&& strncmp((char *)buf, "ECCM2 ", 6) != 0 /* Lenovo Thinkpad W530 Huey ? */
+ && strncmp((char *)buf, "ECCM3 ", 6) != 0 /* Lenovo Thinkpad W530 Huey ? */
&& strncmp((char *)buf, "Cir001", 6) != 0) { /* Huey */
a1logd(p->log,1,"huey_check_unlock: unknown model '%s'\n",buf);
return huey_interp_code((inst *)p, HUEY_UNKNOWN_MODEL);
@@ -920,7 +922,7 @@ huey_read_all_regs(
inst_code ev;
int i;
- a1logd(p->log,2,"huey_check_unlock: about to read all the registers\n");
+ a1logd(p->log,2,"huey_read_all_regs: about to read all the registers\n");
/* Serial number */
if ((ev = huey_rdreg_word(p, &p->ser_no, 0) ) != inst_ok)
@@ -988,7 +990,7 @@ huey_read_all_regs(
return ev;
a1logd(p->log,3,"Integration time = %d\n",p->int_clocks);
- a1logd(p->log,2,"huey_check_unlock: all registers read OK\n");
+ a1logd(p->log,2,"huey_read_all_regs: all registers read OK\n");
return inst_ok;
}
@@ -1671,8 +1673,7 @@ int *cbid) {
* error if it hasn't been initialised.
*/
static inst_code
-huey_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+huey_get_set_opt(inst *pp, inst_opt_type m, ...) {
huey *p = (huey *)pp;
inst_code ev = inst_ok;
@@ -1717,7 +1718,17 @@ huey_get_set_opt(inst *pp, inst_opt_type m, ...)
return huey_set_LEDs(p, mask);
}
- return inst_unsupported;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/huey.h b/spectro/huey.h
index aec96a0..f13056b 100644
--- a/spectro/huey.h
+++ b/spectro/huey.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update huey_interp_error() and huey_interp_code() in huey.c */
/* if anything of these #defines are added or subtracted */
@@ -131,6 +135,9 @@ struct _huey {
/* Constructor */
extern huey *new_huey(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define HUEY_H
#endif /* HUEY_H */
diff --git a/spectro/i1d3.c b/spectro/i1d3.c
index df7d3f0..4562a52 100644
--- a/spectro/i1d3.c
+++ b/spectro/i1d3.c
@@ -2464,6 +2464,8 @@ i1d3_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* On Linux, the i1d3 doesn't seem to close properly, and won't re-open - */
/* something to do with detaching the default HID driver ?? */
#if defined(UNIX_X11)
+ usbflags |= icomuf_detach;
+ usbflags |= icomuf_no_open_clear;
usbflags |= icomuf_reset_before_close;
#endif
/* Open as an HID if available */
@@ -2485,7 +2487,7 @@ i1d3_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Set config, interface, write end point, read end point */
/* ("serial" end points aren't used - the i1d3 uses USB control messages) */
/* We need to detatch the HID driver on Linux */
- if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags | icomuf_detach, 0, NULL))
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, 0, NULL))
!= ICOM_OK) {
a1logd(p->log, 1, "i1d3_init_coms: set_usb_port failed ICOM err 0x%x\n",se);
return i1d3_interp_code((inst *)p, icoms2i1d3_err(se, 0));
@@ -2695,6 +2697,8 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if (!p->inited)
return inst_no_init;
+ a1logd(p->log, 1, "i1d3: i1d3_read_sample called\n");
+
if (p->trig == inst_opt_trig_user) {
if (p->uicallback == NULL) {
@@ -2944,6 +2948,7 @@ static inst_code i1d3_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
i1d3 *p = (i1d3 *)pp;
@@ -2955,6 +2960,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = i1d3_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -3816,8 +3822,7 @@ int *cbid) {
* error if it hasn't been initialised.
*/
static inst_code
-i1d3_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+i1d3_get_set_opt(inst *pp, inst_opt_type m, ...) {
i1d3 *p = (i1d3 *)pp;
inst_code ev;
@@ -4018,7 +4023,18 @@ i1d3_get_set_opt(inst *pp, inst_opt_type m, ...)
if (trans_time_prop != NULL) *trans_time_prop = p->led_trans_time_prop;
return inst_ok;
}
- return inst_unsupported;
+
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/i1d3.h b/spectro/i1d3.h
index bb239df..a7c3b24 100644
--- a/spectro/i1d3.h
+++ b/spectro/i1d3.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update huey_interp_error() and huey_interp_code() in huey.c */
/* if anything of these #defines are added or subtracted */
@@ -79,7 +83,7 @@
typedef enum {
i1d3_disppro = 0, /* i1 DisplayPro */
i1d3_munkdisp = 1, /* ColorMunki Display */
- i1d3_oem = 2, /* OEM */
+ i1d3_oem = 2, /* Generic OEM */
i1d3_nec_ssp = 3, /* NEC SpectraSensor Pro */
i1d3_quato_sh3 = 4, /* Quato Silver Haze 3 */
i1d3_hp_dreamc = 5, /* HP DreameColor */
@@ -169,6 +173,9 @@ struct _i1d3 {
/* Constructor */
extern i1d3 *new_i1d3(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define I1D3_H
#endif /* I1D3_H */
diff --git a/spectro/i1disp.c b/spectro/i1disp.c
index 489c6cd..9e4b01f 100644
--- a/spectro/i1disp.c
+++ b/spectro/i1disp.c
@@ -481,7 +481,7 @@ i1disp_rdexreg_bytes(
) {
unsigned char ibuf[16];
unsigned char obuf[16];
- int rsize;
+ int ooff, rsize;
inst_code ev;
if (p->dtype != 2) /* Only ColorMunki Smile ? */
@@ -493,7 +493,7 @@ i1disp_rdexreg_bytes(
if (len < 0 || (addr + len) > 0x0200)
return i1disp_interp_code((inst *)p, I1DISP_BAD_REG_ADDRESS);
- for (; len > 0; ) {
+ for (ooff = 0; len > 0; ) {
int rlen = len;
if (rlen > 4)
rlen = 4;
@@ -512,7 +512,8 @@ i1disp_rdexreg_bytes(
if (obuf[0] != rlen) /* Number of bytes returned */
return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_VAL);
- memcpy(outp + addr, obuf + 1, rlen);
+ memcpy(outp + ooff, obuf + 1, rlen);
+ ooff += rlen;
addr += rlen;
len -= rlen;
}
@@ -643,6 +644,7 @@ i1d1_take_measurement(
int i;
int edgec[3]; /* Edge count 1..255 for each channel */
inst_code ev;
+ double edge_aim = p->clk_freq;
if (p->inited == 0)
return i1disp_interp_code((inst *)p, I1DISP_NOT_INITED);
@@ -659,13 +661,18 @@ i1d1_take_measurement(
a1logd(p->log, 3, "Initial RGB = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
/* Compute adjusted edge count, aiming */
- /* for count values of clk_freq = 1 second (~1e6). */
+ /* for count values of clk_freq = 1 second (~1e6), */
+ /* or 2 seconds if an older instrument */
+ if (p->stype == i1d1_sencoreIV
+ || p->stype == i1d1_sencoreIII)
+ edge_aim = 2.0 * p->clk_freq;;
+
for (i = 0; i < 3; i++) {
double ns;
- if (p->clk_freq > ((255.0 - 0.5) * rgb[i]))
+ if (edge_aim > ((255.0 - 0.5) * rgb[i]))
ns = 255.0;
else {
- ns = floor(p->clk_freq/rgb[i]) + 0.5;
+ ns = floor(edge_aim/rgb[i]) + 0.5;
if (ns < 1.0)
ns = 1.0;
}
@@ -1254,12 +1261,13 @@ i1disp_take_XYZ_measurement(
for (j = 0; j < 3; j++) {
XYZ[i] += mat[i * 3 + j] * rgb[j];
}
- XYZ[i] *= CALFACTOR; /* Times magic scale factor */
-#ifdef NEVER
- if (p->chroma4)
- XYZ[i] *= 4.0/3.0; /* (Not sure about this factor!) */
-#endif
+
+ /* Magic factors for other devices ?? */
+ if (p->stype == i1d1_sencoreIV)
+ XYZ[i] *= CALFACTOR; /* (Not sure about this factor!) */
+ else
+ XYZ[i] *= CALFACTOR; /* Times magic scale factor */
}
if (!IMODETST(p->mode, inst_mode_emis_ambient)) {
@@ -1402,25 +1410,26 @@ i1disp_check_unlock(
struct {
unsigned char code[4];
- int *flag;
+ i1d2_dtype stype;
} codes[] = {
- { { 'G','r','M','b' }, NULL }, /* "GrMb" i1 Display */
- { { 'L','i','t','e' }, &p->lite }, /* "Lite" i1 Display LT */
- { { 'M','u','n','k' }, &p->munki }, /* "Munk" ColorMunki Create */
- { { 'O','b','i','W' }, &p->hpdream }, /* "ObiW" HP DreamColor */
- { { 'O','b','i','w' }, &p->hpdream }, /* "Obiw" HP DreamColor */
- { { 'C','M','X','2' }, &p->calmanx2 }, /* "CMX2" Calman X2 */
- { { 0x24,0xb6,0xb5,0x13 }, NULL }, /* ColorMunki Smile */
- { { 'S','p','C','3' }, NULL }, /* SpectraCal C3 (Based on Smile) */
- { { 'R','G','B','c' }, NULL }, /* */
- { { 'C','E','C','5' }, NULL }, /* */
- { { 'C','M','C','5' }, NULL }, /* */
- { { 'C','M','G','5' }, NULL }, /* */
- { { 0x00,0x00,0x01,0x00 }, NULL }, /* */
- { { 0x09,0x0b,0x0c,0x0d }, NULL }, /* */
- { { 0x0e,0x0e,0x0e,0x0e }, NULL }, /* */
- { { 0x11,0x02,0xde,0xf0 }, NULL }, /* Barco Chroma 5 ? */
- { { ' ',' ',' ',' ' }, (int *)-1 }
+ { { 'G','r','M','b' }, i1d2_norm }, /* "GrMb" i1 Display */
+ { { 'L','i','t','e' }, i1d2_lite }, /* "Lite" i1 Display LT */
+ { { 'M','u','n','k' }, i1d2_munki }, /* "Munk" ColorMunki Create */
+ { { 'O','b','i','W' }, i1d2_hpdream }, /* "ObiW" HP DreamColor */
+ { { 'O','b','i','w' }, i1d2_hpdream }, /* "Obiw" HP DreamColor */
+ { { 'C','M','X','2' }, i1d1_calmanx2 }, /* "CMX2" Calman X2 */
+ { { 0x24,0xb6,0xb5,0x13 }, i1d2_norm }, /* ColorMunki Smile */
+ { { 'S','p','C','3' }, i1d2_norm }, /* SpectraCal C3 (Based on Smile) */
+ { { 'R','G','B','c' }, i1d2_norm }, /* */
+ { { 'C','E','C','5' }, i1d2_norm }, /* */
+ { { 'C','M','C','5' }, i1d2_norm }, /* */
+ { { 'C','M','G','5' }, i1d2_norm }, /* */
+ { { 0x00,0x00,0x01,0x00 }, i1d2_norm }, /* */
+ { { 0x09,0x0b,0x0c,0x0d }, i1d2_norm }, /* */
+ { { 0x0e,0x0e,0x0e,0x0e }, i1d2_norm }, /* */
+ { { 0x11,0x02,0xde,0xf0 }, i1d2_norm }, /* Barco Chroma 5 ? */
+// { { 0xff,0xff,0xff,0xff }, i1d2_norm }, /* Chroma 5 isn't locked ? */
+ { { ' ',' ',' ',' ' }, -1 }
};
a1logd(p->log, 3, "i1disp: about to check response and unlock instrument if needed\n");
@@ -1433,17 +1442,9 @@ i1disp_check_unlock(
/* Try and unlock it if it is locked */
if ((ev & inst_imask) == I1DISP_LOCKED) {
- /* Reset any flags */
- for (i = 0; ;i++) {
- if (codes[i].flag == (int *)-1)
- break;
- if (codes[i].flag != NULL)
- *codes[i].flag = 0;
- }
-
/* Try each code in turn */
for (i = 0; ;i++) {
- if (codes[i].flag == (int *)-1) {
+ if (codes[i].stype == -1) {
a1logd(p->log, 3, "Failed to find correct unlock code\n");
return i1disp_interp_code((inst *)p, I1DISP_UNKNOWN_MODEL);
}
@@ -1461,8 +1462,9 @@ i1disp_check_unlock(
return ev; /* An error other than being locked */
if (ev == inst_ok) { /* Correct code */
- if (codes[i].flag != NULL)
- *codes[i].flag = 1;
+ p->stype = codes[i].stype;
+ a1logd(p->log, 3, "Unlocked with code '%c%c%c%c'\n",
+ codes[i].code[0], codes[i].code[1], codes[i].code[2], codes[i].code[3]);
break;
}
}
@@ -1485,15 +1487,30 @@ i1disp_check_unlock(
a1logd(p->log, 3, "Version character = 0x%02x = '%c'\n",vv,vv);
- /* Sequel Chroma 4 with vv == 0xff ? */
- /* Barco Chroma 5 with ver = 5.01 and vv = '5' */
- if (ver >= 4.0 && ver < 5.1
- && (vv == 0xff || vv == 0x35)) {
+ /* Barco Chroma 5 with ver = 5.01 vv = '5' */
+ if (ver >= 4.0 && ver < 5.1 && vv == '5') {
p->dtype = 0; /* Sequel Chroma 4 ?? */
- p->chroma4 = 1; /* Treat like an Eye-One Display 1 */
- /* !!! Not fully tested !!! */
+ p->stype = i1d1_chroma4; /* Treat like an Eye-One Display 1 */
+
+ /* Sequel Chroma 4 with vv == 0xff ???? */
+ /* Sencore ColorPro III with ver = 5.01 and vv = 0xff */
+ } else if (ver >= 4.0 && ver < 5.1 && vv == 0xff) {
+ p->dtype = 0; /* Eye-One Display 1 */
+ p->stype = i1d1_sencoreIII;
+
+ /* Sencore ColorPro IV with ver = 5.01 and vv = 'L' */
+ } else if (ver >= 4.0 && ver < 5.1 && vv == 'L') {
+ p->dtype = 0; /* Eye-One Display 1 */
+ p->stype = i1d1_sencoreIV; /* Treat like an Eye-One Display 1 */
+
+ /* Sencore ColorPro V with ver = 5.01 and vv = 'B' */
+ } else if (ver >= 4.0 && ver < 5.1 && vv == 'B') {
+ p->dtype = 0; /* Eye-One Display 1 */
+ p->stype = i1d1_sencoreV; /* Treat like an Eye-One Display 1 */
+
} else if (ver >= 5.1 && ver <= 5.3 && vv == 'L') {
p->dtype = 0; /* Eye-One Display 1 */
+
} else if (ver >= 6.0 && ver <= 6.29 && vv == 'L') {
p->dtype = 1; /* Eye-One Display 2 */
@@ -1506,7 +1523,7 @@ i1disp_check_unlock(
} else {
/* Reject any version or model we don't know about */
- a1logv(p->log, 1, "Version string = %3.1f\nID character = 0x%02x = '%c'\n",ver,vv,vv);
+ a1logd(p->log, 1, "Version string = %5.3f\nID character = 0x%02x = '%c'\n",ver,vv,vv);
return i1disp_interp_code((inst *)p, I1DISP_UNKNOWN_VERS_ID);
}
@@ -1998,6 +2015,7 @@ inst_code i1disp_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
i1disp *p = (i1disp *)pp;
@@ -2009,6 +2027,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = i1disp_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -2588,8 +2607,7 @@ int *cbid) {
* was assume that all of these can be done before initialisation.
*/
static inst_code
-i1disp_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+i1disp_get_set_opt(inst *pp, inst_opt_type m, ...) {
i1disp *p = (i1disp *)pp;
inst_code ev;
@@ -2600,7 +2618,17 @@ i1disp_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- return inst_unsupported;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/i1disp.h b/spectro/i1disp.h
index 45e21db..eada827 100644
--- a/spectro/i1disp.h
+++ b/spectro/i1disp.h
@@ -35,6 +35,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update i1disp_interp_error() and i1disp_interp_code() in i1disp.c */
/* if anything of these #defines are added or subtracted */
@@ -72,17 +76,28 @@
#define I1DISP_WRONG_DEVICE 0x26
#define I1DISP_LOCKED 0x27
+/* Sub-type of instrument (i.e. based on vers, char code, unlock code) */
+typedef enum {
+ i1d2_norm = 0, /* Normal (i1d1, i1d2, Smile) */
+ i1d2_lite = 1, /* "Lite" */
+ i1d2_munki = 2, /* "Munk" */
+ i1d2_hpdream = 3, /* "ObiW" */
+ i1d1_calmanx2 = 4, /* "CMX2" */
+ i1d1_chroma4 = 5, /* Chroma 4 */
+ i1d1_chroma5 = 6, /* Chroma 5 */
+ i1d1_sencoreIII = 7, /* Sencore ColorPro III */
+ i1d1_sencoreIV = 8, /* Sencore ColorPro IV */
+ i1d1_sencoreV = 9 /* Sencore ColorPro V */
+} i1d2_dtype;
+
/* I1DISP communication object */
struct _i1disp {
INST_OBJ_BASE
- int dtype; /* Device type: 0 = i1D1, 1 = i1D2, 2 = Smile */
- int lite; /* i1D2: 0 = normal, 1 = "Lite" */
- int munki; /* i1D2: 0 = normal, 1 = "Munk" */
- int hpdream; /* i1D2: 0 = normal, 1 = "ObiW" */
- int calmanx2; /* i1D2: 0 = normal, 1 = "CMX2" */
- int chroma4; /* 0 = other, 1 = Sequel Chroma 4 (i1D1 based) */
+ int dtype; /* Device type: 0 = i1D1, 1 = i1D2, 2 = Smile */
+ i1d2_dtype stype; /* Sub type */
+
inst_mode mode; /* Currently selected mode */
inst_opt_type trig; /* Reading trigger mode */
@@ -169,6 +184,9 @@ struct _i1disp {
/* Constructor */
extern i1disp *new_i1disp(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define I1DISP_H
#endif /* I1DISP_H */
diff --git a/spectro/i1pro.c b/spectro/i1pro.c
index 816aee5..44614d2 100644
--- a/spectro/i1pro.c
+++ b/spectro/i1pro.c
@@ -3,7 +3,9 @@
* Argyll Color Correction System
*
* Gretag i1Monitor & i1Pro related functions
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 24/11/2006
*
@@ -85,7 +87,7 @@ i1pro_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
i1pro *p = (i1pro *) pp;
int rsize, se;
icomuflags usbflags = icomuf_none;
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* If the X-Rite software has been installed, then there may */
/* be a daemon process that has the device open. Kill that process off */
/* so that we can open it here, before it re-spawns. */
@@ -95,10 +97,10 @@ i1pro_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
NULL
};
int retries = 20;
-#else /* !__APPLE__ */
+#else /* !UNIX_APPLE */
char **pnames = NULL;
int retries = 0;
-#endif /* !__APPLE__ */
+#endif /* !UNIX_APPLE */
a1logd(p->log, 2, "i1pro_init_coms: called\n");
@@ -238,7 +240,7 @@ ipatch *vals) { /* Pointer to array of instrument patch values */
if (!p->inited)
return inst_no_init;
- rv = i1pro_imp_measure(p, vals, npatch, 1);
+ rv = i1pro_imp_measure(p, vals, npatch, instClamp);
return i1pro_interp_code(p, rv);
}
@@ -328,6 +330,7 @@ static inst_code i1pro_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
i1pro *p = (i1pro *)pp;
@@ -338,7 +341,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
- rv = i1pro_imp_calibrate(p, calt, calc, id);
+ rv = i1pro_imp_calibrate(p, calt, calc, idtype, id);
return i1pro_interp_code(p, rv);
}
@@ -385,8 +388,10 @@ i1pro_interp_error(inst *pp, i1pro_code ec) {
return "EEProm key is the wrong type";
case I1PRO_DATA_KEY_CORRUPT:
return "EEProm key table seems to be corrupted";
- case I1PRO_DATA_KEY_COUNT:
- return "EEProm key table count is too big or small";
+ case I1PRO_DATA_KEY_COUNT_SMALL:
+ return "EEProm key table size is too small for expected number of keys";
+ case I1PRO_DATA_KEY_COUNT_LARGE:
+ return "EEProm key table size is too large for expected number of keys";
case I1PRO_DATA_KEY_UNKNOWN:
return "EEProm unknown key type";
case I1PRO_DATA_KEY_MEMRANGE:
@@ -448,7 +453,7 @@ i1pro_interp_error(inst *pp, i1pro_code ec) {
case I1PRO_RD_TOOMANYPATCHES:
return "Too many patches";
case I1PRO_RD_NOTENOUGHSAMPLES:
- return "Not enough samples per patch";
+ return "Not enough samples per patch - Slow Down!";
case I1PRO_RD_NOFLASHES:
return "No flashes recognized";
case I1PRO_RD_NOAMBB4FLASHES:
@@ -557,11 +562,32 @@ i1pro_interp_code(i1pro *p, i1pro_code ec) {
case I1PRO_CAL_SETUP:
return inst_cal_setup | ec;
+ case I1PRO_DATA_COUNT:
+ case I1PRO_DATA_BUFSIZE:
+ case I1PRO_DATA_MAKE_KEY:
+ case I1PRO_DATA_MEMORY:
+ case I1PRO_DATA_KEYNOTFOUND:
+ case I1PRO_DATA_WRONGTYPE:
+ case I1PRO_DATA_KEY_CORRUPT:
+ case I1PRO_DATA_KEY_COUNT_SMALL:
+ case I1PRO_DATA_KEY_COUNT_LARGE:
+ case I1PRO_DATA_KEY_UNKNOWN:
+ case I1PRO_DATA_KEY_MEMRANGE:
+ case I1PRO_DATA_KEY_ENDMARK:
+
case I1PRO_HW_HIGHPOWERFAIL:
+ case I1PRO_HW_EE_SIZE:
case I1PRO_HW_EE_SHORTREAD:
+ case I1PRO_HW_EE_SHORTWRITE:
case I1PRO_HW_ME_SHORTREAD:
case I1PRO_HW_ME_ODDREAD:
+ case I1PRO_HW_SW_SHORTREAD:
+ case I1PRO_HW_LED_SHORTWRITE:
+ case I1PRO_HW_UNEX_SPECPARMS:
case I1PRO_HW_CALIBINFO:
+ case I1PRO_WL_TOOLOW:
+ case I1PRO_WL_SHAPE:
+ case I1PRO_WL_ERR2BIG:
return inst_hardware_fail | ec;
case I1PRO_RD_DARKREADINCONS:
@@ -718,8 +744,7 @@ static inst_code i1pro_set_mode(inst *pp, inst_mode m) {
* error if it hasn't been initialised.
*/
static inst_code
-i1pro_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+i1pro_get_set_opt(inst *pp, inst_opt_type m, ...) {
i1pro *p = (i1pro *)pp;
if (m == inst_opt_initcalib) { /* default */
@@ -785,6 +810,81 @@ i1pro_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
+ /* Set xcalstd */
+ if (m == inst_opt_set_xcalstd) {
+ i1proimp *imp = (i1proimp *)p->m;
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ imp->target_calstd = standard;
+
+ return inst_ok;
+ }
+
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ i1proimp *imp = (i1proimp *)p->m;
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (imp->target_calstd == xcalstd_native)
+ *standard = imp->native_calstd; /* If not overridden */
+ else
+ *standard = imp->target_calstd; /* Overidden std. */
+
+ return inst_ok;
+ }
+
+ /* Return the white calibration tile spectrum */
+ /* (We always return the normal rez. reference values) */
+ if (m == inst_opt_get_cal_tile_sp) {
+ i1proimp *imp = (i1proimp *)p->m;
+ xspect *sp;
+ inst_code rv;
+ va_list args;
+ int i;
+
+ va_start(args, m);
+ sp = va_arg(args, xspect *);
+ va_end(args);
+
+ if (imp->white_ref[0] == NULL)
+ return inst_no_init;
+
+ sp->spec_n = imp->nwav[0];
+ sp->spec_wl_short = imp->wl_short[0];
+ sp->spec_wl_long = imp->wl_long[0];
+ sp->norm = 100.0;
+
+ for (i = 0; i < sp->spec_n; i++)
+ sp->spec[i] = imp->white_ref[0][i] * 100.0;
+
+ return inst_ok;
+ }
+
+ /* Lamp drift remediation */
+ if (m == inst_opt_lamp_remediate) {
+ i1pro_code ev;
+ va_list args;
+ double seconds;
+
+ va_start(args, m);
+ seconds = va_arg(args, double);
+ va_end(args);
+
+ ev = i1pro_imp_lamp_fix(p, seconds);
+
+ return i1pro_interp_code(p, ev);
+ }
+
/* Use default implementation of other inst_opt_type's */
{
inst_code rv;
diff --git a/spectro/i1pro.h b/spectro/i1pro.h
index 4366e4f..e449f2c 100644
--- a/spectro/i1pro.h
+++ b/spectro/i1pro.h
@@ -4,7 +4,9 @@
* Argyll Color Correction System
*
* Gretag i1Pro related defines
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 24/11/2006
*
@@ -15,6 +17,10 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/*
If you make use of the instrument driver code here, please note
that it is the author(s) of the code who take responsibility
@@ -52,5 +58,9 @@ struct _i1pro {
/* Constructor */
extern i1pro *new_i1pro(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
+
#define I1PRO_H
#endif /* I1PRO_H */
diff --git a/spectro/i1pro_imp.c b/spectro/i1pro_imp.c
index 8577f8c..a8cb9e0 100644
--- a/spectro/i1pro_imp.c
+++ b/spectro/i1pro_imp.c
@@ -3,7 +3,9 @@
* Argyll Color Correction System
*
* Gretag i1Pro implementation functions
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 24/11/2006
*
@@ -34,6 +36,10 @@
/* TTBD:
+ Would be nice to have option to save raw scan data to .ti3 file,
+ and then have a utility/option to replay it through scan
+ recognition, to be able to help remote diagnose scan problems.
+
Some things probably aren't quite correct:
The way the sensor saturation and optimal target is
computed probably doesn't account for the dark level
@@ -46,9 +52,6 @@
(see i1d3.c). Whether this will noticably improve repeatibility
remains to be seen.
- Would be nice to have option to save raw scan data to .ti3 file,
- and then have a utility/option to replay it through scan
- recognition, to be able to help remote diagnose scan problems.
*/
/*
@@ -112,7 +115,7 @@
#define DCALTOUT2 ( 1 * 60 * 60) /* [1 Hr] i1pro2 Dark Calibration timeout in seconds */
#define WCALTOUT ( 1 * 60 * 60) /* [1 Hr] White Calibration timeout in seconds */
-#define MAXSCANTIME 20.0 /* [20] Maximum scan time in seconds */
+#define MAXSCANTIME 30.0 /* [30] Maximum scan time in seconds */
#define SW_THREAD_TIMEOUT (10 * 60.0) /* [10 Min] Switch read thread timeout */
#define SINGLE_READ /* [Def] Use a single USB read for scan to eliminate latency issues. */
@@ -131,6 +134,7 @@
#undef TEST_DARK_INTERP /* Test out the dark interpolation (need DEBUG for plot) */
#undef PATREC_DEBUG /* Print & Plot patch/flash recognition information */
#undef PATREC_ALLBANDS /* Plot all bands of scan */
+#undef PATREC_SAVETRIMMED /* Saved trimmed raw to file "i1pro_raw_trimed_N.csv */
#undef IGNORE_WHITE_INCONS /* Ignore define reference reading inconsistency */
#undef HIGH_RES_DEBUG
#undef HIGH_RES_PLOT
@@ -138,8 +142,8 @@
#undef PLOT_BLACK_SUBTRACT /* Plot temperature corrected black subtraction */
#undef FAKE_AMBIENT /* Fake the ambient mode for a Rev A */
-#define MATCH_SPOT_OMD /* [Def] Match Original Manufacturers Driver. Reduce */
- /* integration time and lamp turn on time */
+#undef USE_SPOT_OMD /* [Und] Use Original Manufacturers Driver timing. Reduce */
+ /* integration time and lamp turn on time. */
#define DISP_INTT 2.0 /* Seconds per reading in display spot mode */
/* More improves repeatability in dark colors, but limits */
@@ -171,6 +175,7 @@
#include "i1pro.h"
#include "i1pro_imp.h"
+#include "xrga.h"
/* - - - - - - - - - - - - - - - - - - */
#define LAMP_OFF_TIME 1500 /* msec to make sure lamp is dark for dark measurement */
@@ -448,9 +453,26 @@ i1pro_code i1pro_imp_init(i1pro *p) {
i1pro_code ev = I1PRO_OK;
unsigned char *eeprom; /* EEProm contents, i1pro = half, i1pro2 = full */
int len = 8192;
+ char *envv;
a1logd(p->log,5,"i1pro_init:\n");
+ m->native_calstd = xcalstd_gmdi; /* Rev A-D */
+ if (p->itype == instI1Pro2) {
+ m->native_calstd = xcalstd_xrga; /* Rev E */
+ }
+ m->target_calstd = xcalstd_native; /* Default to native calibration */
+
+ /* Honor Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ m->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ m->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ m->target_calstd = xcalstd_gmdi;
+ }
+
/* Revert to i1pro if i1pro2 driver is not enabled */
if (p->itype == instI1Pro2
#ifdef ENABLE_2
@@ -1006,22 +1028,27 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->dadaptime = 0.10;
s->wadaptime = 0.10;
-#ifdef MATCH_SPOT_OMD
- s->lamptime = 0.18; /* Lamp turn on time, close to OMD */
- /* (Not ideal, but partly compensated by calib.) */
- /* (The actual value the OMD uses is 0.20332) */
- s->dcaltime = 0.05; /* Longer than the original driver for lower */
- /* noise, and lamptime has been reduces to */
- /* compensate. (OMD uses 0.014552) */
- s->wcaltime = 0.05;
- s->dreadtime = 0.05;
- s->wreadtime = 0.05;
+#ifdef USE_SPOT_OMD
+ s->lamptime = 0.20332; /* (Lamp doesn't stabilize with this) */
+ s->dcaltime = 0.02366;
+ s->wcaltime = 0.02366;
+ s->dreadtime = 0.02366;
+ s->wreadtime = 0.02366;
#else
- s->lamptime = 0.5; /* This should give better accuracy, and better */
- s->dcaltime = 0.5; /* match the scan readings. Difference is about */
- s->wcaltime = 0.5; /* 0.1 DE though, but would be lost in the */
- s->dreadtime = 0.5; /* repeatability noise... */
- s->wreadtime = 0.5;
+#ifndef NEVER
+ s->lamptime = 0.25; /* This should give better accuracy */
+ s->dcaltime = 0.05; /* without increasing lamp usage much. */
+ s->wcaltime = 0.05; /* Make it too large (ie. 1.0 sec total) */
+ s->dreadtime = 0.05; /* and it will dirty the i1pro2 lamp quickly */
+ s->wreadtime = 0.05; /* though. */
+#else
+# pragma message("######### i1pro_imp.c Dirty Lamp timing !!!!! ########")
+ s->lamptime = 0.5; /* Dirty up the lamp. */
+ s->dcaltime = 2.0;
+ s->wcaltime = 2.0;
+ s->dreadtime = 2.0;
+ s->wreadtime = 2.0;
+#endif
#endif
s->maxscantime = 0.0;
s->min_wl = HIGHRES_REF_MIN;/* Too much stray light below this */
@@ -1037,13 +1064,12 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->targoscale = 0.25;
else
s->targoscale = 0.5;
-
- s->lamptime = 0.5; /* Lamp turn on time - lots to match scan */
+ s->lamptime = 0.5; /* Lamp turn on time - lots to match scan */
s->dadaptime = 0.10;
s->wadaptime = 0.10;
s->dcaltime = 0.5;
- s->wcaltime = 0.5;
- s->dreadtime = 0.10;
+ s->wcaltime = 2.5; /* Lots to get lamp up to temp */
+ s->dreadtime = 0.10; /* and to match OMD scan cal. on time */
s->wreadtime = 0.10;
s->maxscantime = MAXSCANTIME;
s->min_wl = HIGHRES_REF_MIN; /* Too much stray light below this */
@@ -1058,7 +1084,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->adaptive = 0;
s->inttime = DISP_INTT; /* Default disp integration time (ie. 2.0 sec) */
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dark_int_time = s->inttime;
s->dark_int_time2 = DISP_INTT2; /* Alternate disp integration time (ie. 0.8) */
s->dark_int_time3 = DISP_INTT3; /* Alternate disp integration time (ie. 0.3) */
@@ -1083,7 +1109,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->emiss = 1;
s->adaptive = 1;
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dadaptime = 0.0;
s->wadaptime = 0.10;
s->dcaltime = 1.0;
@@ -1100,7 +1126,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->scan = 1;
s->adaptive = 1; /* ???? */
s->inttime = m->min_int_time; /* Maximize scan rate */
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dark_int_time = s->inttime;
if (m->fwrev >= 301)
s->targoscale = 0.25; /* (We're not using scan targoscale though) */
@@ -1132,7 +1158,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->ambient = 1;
s->adaptive = 1;
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dadaptime = 0.0;
s->wadaptime = 0.10;
s->dcaltime = 1.0;
@@ -1161,7 +1187,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->flash = 1;
s->inttime = m->min_int_time; /* Maximize scan rate */
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dark_int_time = s->inttime;
if (m->fwrev >= 301)
s->targoscale = 0.25; /* (We're not using scan targoscale though) */
@@ -1181,7 +1207,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->trans = 1;
s->adaptive = 1;
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dadaptime = 0.10;
s->wadaptime = 0.10;
s->dcaltime = 1.0;
@@ -1202,7 +1228,7 @@ i1pro_code i1pro_imp_init(i1pro *p) {
else
s->targoscale = 0.5;
- s->lamptime = 0.20; /* ???? */
+ s->lamptime = 0.0;
s->dadaptime = 0.10;
s->wadaptime = 0.10;
s->dcaltime = 1.0;
@@ -1483,6 +1509,7 @@ i1pro_code i1pro_imp_calibrate(
i1pro *p,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+ inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
i1pro_code ev = I1PRO_OK;
@@ -2250,6 +2277,16 @@ i1pro_code i1pro_imp_calibrate(
s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
s->cal_factor[1], m->white_ref[1], s->cal_factor[1],
!s->scan); /* Use this for emis hires fine tune if not scan */
+
+ /* Print white lamp magnitude to track lamp darkening */
+ if (p->log != NULL && p->log->debug >= 1) {
+ double sum = 0.0;
+ for (i = 0; i < m->nwav[0]; i++)
+ sum += 1.0/s->cal_factor[0][i];
+
+ a1logd(p->log,1,"Refl. lamp magnitude = %e\n",sum);
+ }
+
if (ev == I1PRO_RD_TRANSWHITEWARN) /* Shouldn't happen ? */
ev = I1PRO_OK;
if (ev != I1PRO_OK) {
@@ -2365,7 +2402,8 @@ i1pro_code i1pro_imp_calibrate(
/* Do ref_white first in case we are doing a high res fine tune. */
if (*calt & (inst_calt_ref_dark | inst_calt_ref_white)) {
- sprintf(id, "Serial no. %d",m->serno);
+ *idtype = inst_calc_id_ref_sn;
+ sprintf(id, "%d",m->serno);
if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) {
/* Calibrate using white tile */
*calc = inst_calc_man_ref_white;
@@ -2373,6 +2411,7 @@ i1pro_code i1pro_imp_calibrate(
}
} else if (*calt & inst_calt_wavelength) { /* Wavelength calibration */
if (cs->emiss && cs->ambient) {
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_am_dark) {
/* Calibrate using ambient adapter */
@@ -2380,7 +2419,8 @@ i1pro_code i1pro_imp_calibrate(
return I1PRO_CAL_SETUP;
}
} else {
- sprintf(id, "Serial no. %d",m->serno);
+ *idtype = inst_calc_id_ref_sn;
+ sprintf(id, "%d",m->serno);
if ((*calc & inst_calc_cond_mask) != inst_calc_man_ref_white) {
/* Calibrate using white tile */
*calc = inst_calc_man_ref_white;
@@ -2388,6 +2428,7 @@ i1pro_code i1pro_imp_calibrate(
}
}
} else if (*calt & inst_calt_em_dark) { /* Emissive Dark calib */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_em_dark) {
/* Any sort of dark reference */
@@ -2395,18 +2436,21 @@ i1pro_code i1pro_imp_calibrate(
return I1PRO_CAL_SETUP;
}
} else if (*calt & inst_calt_trans_dark) { /* Transmissvice dark */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_trans_dark) {
*calc = inst_calc_man_trans_dark;
return I1PRO_CAL_SETUP;
}
} else if (*calt & inst_calt_trans_vwhite) {/* Transmissvice white for emulated transmission */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_trans_white) {
*calc = inst_calc_man_trans_white;
return I1PRO_CAL_SETUP;
}
} else if (*calt & inst_calt_emis_int_time) {
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_emis_white) {
*calc = inst_calc_emis_white;
@@ -2438,10 +2482,13 @@ i1pro_code i1pro_imp_calibrate(
if (m->transwarn) {
*calc = inst_calc_message;
- if (m->transwarn & 2)
+ if (m->transwarn & 2) {
+ *idtype = inst_calc_id_trans_low;
strcpy(id, "Warning: Transmission light source is too low for accuracy!");
- else
+ } else {
+ *idtype = inst_calc_id_trans_wl;
strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
+ }
m->transwarn = 0;
}
@@ -2458,6 +2505,51 @@ int icoms2i1pro_err(int se) {
}
/* - - - - - - - - - - - - - - - - */
+/* Do a dummy reflective read, to fix Lamp Drift. */
+
+i1pro_code i1pro_imp_lamp_fix(
+i1pro *p,
+double seconds) { /* Number of seconds to turn lamp on for */
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ int nummeas;
+ double inttime;
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ i1p_mode cmode = m->mmode; /* Remember current mode */
+
+ if (seconds > (5 * 60.0)) {
+ a1loge(p->log, inst_internal_error, "i1pro_imp_lamp_fix %f sec is too long\n",seconds);
+ return I1PRO_INT_ASSERT;
+ }
+
+ m->mmode = i1p_refl_spot; /* Override current mode */
+ inttime = 0.2; /* Constrain buffer size */
+ nummeas = (int)(seconds/inttime + 0.5);
+ bsize = m->nsen * 2 * nummeas; /* 16 bit raw values */
+
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ m->mmode = cmode;
+ a1logd(p->log,1,"i1pro_read_patches malloc %d bytes failed (11)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* Trigger measure and gather raw readings */
+ a1logd(p->log, 1, "i1pro_imp_lamp_fix %f seconds\n",seconds);
+ if ((ev = i1pro_read_patches_1(p, nummeas, nummeas, &inttime, 0,
+ NULL, buf, bsize)) != I1PRO_OK) {
+ m->mmode = cmode;
+ free(buf);
+ return ev;
+ }
+
+ m->mmode = cmode;
+ free(buf);
+
+ return I1PRO_OK;
+}
+
+/* - - - - - - - - - - - - - - - - */
/* Measure a display update delay. It is assumed that */
/* white_stamp(init) has been called, and then a */
/* white to black change has been made to the displayed color, */
@@ -2519,7 +2611,7 @@ int *pinstmsec) { /* Return instrument latency in msec */
}
if (m->whitestamp < 0.0) {
- a1logd(p->log, 1, "i1d3_meas_delay: White transition wasn't timestamped\n");
+ a1logd(p->log, 1, "i1pro_meas_delay: White transition wasn't timestamped\n");
return inst_internal_error;
}
@@ -2940,8 +3032,13 @@ i1pro_code i1pro_imp_measure(
/* Indicate to the user that they can now scan the instrument, */
/* after a little delay that allows for the instrument reaction time. */
if (s->scan) {
- /* 500msec delay, 1KHz for 200 msec */
- msec_beep(200 + (int)(s->lamptime * 1000.0 + 0.5), 1000, 200);
+ int delay = 200 + (int)(s->lamptime * 1000.0 + 0.5);
+ if (p->eventcallback != NULL) {
+ issue_scan_ready((inst *)p, delay);
+ } else {
+ /* delay then 1KHz for 200 msec */
+ msec_beep(delay, 1000, 200);
+ }
}
/* Retry loop for certaing cases */
@@ -4121,6 +4218,7 @@ i1pro_code i1pro_save_calibration(i1pro *p) {
i1pnonv x;
int ss;
int argyllversion = ARGYLL_VERSION;
+ int isRevE = p->itype == instI1Pro2 ? 1 : 0;
strcpy(nmode, "w");
#if !defined(O_CREAT) && !defined(_O_CREAT)
@@ -4157,6 +4255,7 @@ i1pro_code i1pro_save_calibration(i1pro *p) {
write_ints(&x, fp, &argyllversion, 1);
write_ints(&x, fp, &ss, 1);
write_ints(&x, fp, &m->serno, 1);
+ write_ints(&x, fp, &isRevE, 1);
write_ints(&x, fp, (int *)&m->nraw, 1);
write_ints(&x, fp, (int *)&m->nwav[0], 1);
write_ints(&x, fp, (int *)&m->nwav[1], 1);
@@ -4242,6 +4341,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
FILE *fp;
i1pnonv x;
int argyllversion;
+ int isRevE;
int ss, serno, nraw, nwav0, nwav1, nbytes, chsum1, chsum2;
strcpy(nmode, "r");
@@ -4286,6 +4386,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
read_ints(&x, fp, &argyllversion, 1);
read_ints(&x, fp, &ss, 1);
read_ints(&x, fp, &serno, 1);
+ read_ints(&x, fp, &isRevE, 1);
read_ints(&x, fp, &nraw, 1);
read_ints(&x, fp, &nwav0, 1);
read_ints(&x, fp, &nwav1, 1);
@@ -4293,6 +4394,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
|| argyllversion != ARGYLL_VERSION
|| ss != (sizeof(i1pro_state) + sizeof(i1proimp))
|| serno != m->serno
+ || isRevE != (p->itype == instI1Pro2 ? 1 : 0)
|| nraw != m->nraw
|| nwav0 != m->nwav[0]
|| nwav1 != m->nwav[1]) {
@@ -4398,6 +4500,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
read_ints(&x, fp, &argyllversion, 1);
read_ints(&x, fp, &ss, 1);
read_ints(&x, fp, &m->serno, 1);
+ read_ints(&x, fp, &isRevE, 1);
read_ints(&x, fp, (int *)&m->nraw, 1);
read_ints(&x, fp, (int *)&m->nwav[0], 1);
read_ints(&x, fp, (int *)&m->nwav[1], 1);
@@ -5323,6 +5426,7 @@ i1pro_code i1pro_read_patches_2(
} else {
a1logd(p->log,3,"Number of patches measured = %d\n",nmeasuered);
+{
/* Recognise the required number of ref/trans patch locations, */
/* and average the measurements within each patch. */
if ((ev = i1pro_extract_patches_multimeas(p, &rv, absraw, numpatches, multimes,
@@ -5332,6 +5436,7 @@ i1pro_code i1pro_read_patches_2(
a1logd(p->log,2,"i1pro_read_patches_2 spot read failed at i1pro_extract_patches_multimeas\n");
return ev;
}
+}
}
}
free_dmatrix(multimes, 0, nmeasuered-1, -1, m->nraw-1);
@@ -5532,7 +5637,7 @@ i1pro_code i1pro_read_patches_all(
unsigned int bsize;
int rv = 0;
- bsize = m->nsen * 2 * numpatches;
+ bsize = m->nsen * 2 * numpatches; /* 16 bit raw values */
if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
a1logd(p->log,1,"i1pro_read_patches malloc %d bytes failed (11)\n",bsize);
return I1PRO_INT_MALLOC;
@@ -5711,6 +5816,11 @@ i1pro_trigger_one_measure(
int measmodeflags; /* Measurement mode command flags */
int measmodeflags2; /* Rev E Measurement mode command flags */
+ /* Sanity check in case bad value was restored, due to switch */
+ /* from Rev A-D to Rev E mode. */
+ if (*inttime < m->min_int_time)
+ *inttime = m->min_int_time;
+
/* The Rev E measure mode has it's own settings */
if (p->itype == instI1Pro2) {
m->intclkp = m->intclkp2; /* From i1pro2_getmeaschar() ? */
@@ -6378,7 +6488,7 @@ i1pro_code i1pro_extract_patches_multimeas(
#ifdef PATREC_DEBUG
/* Plot out 6 lots of 8 values each */
- plot = dmatrixz(0, 8, 0, nummeas-1);
+ plot = dmatrixz(0, 11, 0, nummeas-1);
// for (j = 45; j <= (m->nraw-8); j += 100) /* Do just one band */
#ifdef PATREC_ALLBANDS
for (j = 0; j <= (m->nraw-8); j += 8) /* Plot all the bands */
@@ -6500,7 +6610,6 @@ i1pro_code i1pro_extract_patches_multimeas(
/* to skew slightly towards the center */
for (k = 0; k < FW; k++) {
double wt;
-
wt = fabs(2.0 * k - (FW -1.0))/(FW-1.0);
dev[k] += wt * bdev;
}
@@ -6689,6 +6798,7 @@ i1pro_code i1pro_extract_patches_multimeas(
break;
pat[npat].no++;
}
+
avglegth += (double) pat[npat].no;
npat++;
}
@@ -6812,20 +6922,80 @@ i1pro_code i1pro_extract_patches_multimeas(
a1logd(p->log,7,"Patch %d, start %d, length %d:\n",i, pat[i].ss, pat[i].no, pat[i].use);
}
- /* Now trim the patches simply by shrinking their windows */
+#ifdef NEVER /* [Und] - doesn't seem as good for normal patch sizes. */
+ /* Now trim the patches by expanding the spacers/transitions */
for (k = 1; k < (npat-1); k++) {
- int nno, trim;
+ int sw, xsw, trim;
if (pat[k].use == 0)
continue;
+
+printf("Patch %d @ %d len %d ->",k,pat[k].ss,pat[k].no);
+ /* Figure the previous spacer width */
+ sw = pat[k].ss - (pat[k-1].ss + pat[k-1].no);
+ xsw = (sw * 170 + 85)/100; /* Expand spacer by 170% */
+ trim = (xsw - sw + 1)/2; /* Move start of patch half that expansion */
+ pat[k].ss += trim;
+ pat[k].no -= trim;
+
+ /* Figure the next spacer width */
+ sw = pat[k+1].ss - (pat[k].ss + pat[k].no);
+ xsw = (sw * 170 + 85)/100; /* Expand spacer by 170% */
+ trim = (xsw - sw + 1)/2; /* Move end of patch half that expansion */
+ pat[k].no -= trim;
+
+ if (pat[k].no < 0)
+ pat[k].no = 0;
+printf(" @ %d len %d\n",pat[k].ss,pat[k].no);
+ }
+#else
+ /* Now trim the patches by shrinking their windows */
+ for (k = 1; k < (npat-1); k++) {
+ int nno, trim;
+ if (pat[k].use == 0)
+ continue;
- nno = (pat[k].no * 3)/4;
- trim = (pat[k].no - nno)/2;
+// nno = (pat[k].no * 3 + 0)/4; /* Trim to 75% & round down */
+ nno = (pat[k].no * 2 + 0)/3; /* Trim to 66% & round down [def] */
+// nno = (pat[k].no * 2 + 0)/4; /* Trim to 50% & round down */
+ trim = (pat[k].no - nno + 1)/2;
pat[k].ss += trim;
pat[k].no = nno;
}
+#endif
+
+#ifdef PATREC_SAVETRIMMED /* Save debugging file */
+ {
+ static int filen = 0; /* Debug file index */
+ char fname[100];
+ FILE *fp;
+
+ sprintf(fname, "i1pro_raw_trimed_%d.csv",filen++);
+
+ if ((fp = fopen(fname, "w")) == NULL)
+ error("Unable to open debug output file '%'",fname);
+
+ /* Create fake "slope" value that marks patches */
+ for (i = 0; i < nummeas; i++)
+ slope[i] = 1.0;
+ for (k = 1; k < (npat-1); k++) {
+ if (pat[k].use == 0)
+ continue;
+ for (i = pat[k].ss; i < (pat[k].ss + pat[k].no); i++)
+ slope[i] = 0.0;
+ }
+
+ for (i = 0; i < nummeas; i++) {
+ fprintf(fp, "%f\t",slope[i]);
+ for (j = 0; j < m->nraw; j++)
+ fprintf(fp, "%f\t", multimeas[i][j]/maxval[j]);
+ fprintf(fp, "\n");
+ }
+ fclose(fp);
+ }
+#endif
#ifdef PATREC_DEBUG
a1logd(p->log,7,"After trimming got:\n");
@@ -6846,6 +7016,17 @@ i1pro_code i1pro_extract_patches_multimeas(
}
printf("Trimmed output:\n");
+#ifdef PATREC_ALLBANDS
+ for (j = 0; j <= (m->nraw-9); j += 9) { /* Plot all the bands, 9 at a time */
+ for (i = 0; i < nummeas; i++) {
+ for (k = 0; k < 9; k++)
+ plot[k][i] = multimeas[i][j+k]/maxval[j+k];
+ plot[10][i] = (double)i;
+ }
+ printf("Bands %d - %d\n",j,j+9);
+ do_plot10(plot[10], slope, plot[0], plot[1], plot[2], plot[3], plot[4], plot[5], plot[6], plot[7], plot[8], nummeas, 0);
+ }
+#else
for (i = 0; i < nummeas; i++) {
int jj;
for (jj = 0, j = b_lo; jj < 6 && j < b_hi; jj++, j += ((b_hi-b_lo)/6)) {
@@ -6856,8 +7037,9 @@ i1pro_code i1pro_extract_patches_multimeas(
}
}
for (i = 0; i < nummeas; i++)
- plot[6][i] = (double)i;
- do_plot6(plot[6], slope, plot[0], plot[1], plot[2], plot[3], plot[4], nummeas);
+ plot[10][i] = (double)i;
+ do_plot6(plot[10], slope, plot[0], plot[1], plot[2], plot[3], plot[4], nummeas);
+#endif
#endif /* PATREC_DEBUG */
#ifdef PATREC_DEBUG
@@ -7884,6 +8066,8 @@ i1pro_code i1pro2_match_wl_meas(i1pro *p, double *pled_off, double *wlraw) {
/* given the current wl_led_off, and set them as current, */
/* using triangular filters of the lagrange interpolation of the */
/* CCD values (i.e. the same type of filter used by the OEM driver) */
+/* [ Interestingly, the resulting filter shape is a bit like lanczos2, */
+/* but not identical. ] */
i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
i1proimp *m = (i1proimp *)p->m;
i1pro_state *s = &m->ms[m->mmode];
@@ -7979,6 +8163,12 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
wlcop[i] = 0.0;
/* for each Lagrange interpolation position (adjacent CCD locations) */
+ /* create the Lagrange and then accuumulate the integral of the convolution */
+ /* of the overlap of the central region, with the triangle of our */
+ /* underlying re-sampling filter. */
+ /* (If we were to run out of enough source points for the Lagrange to */
+ /* encompas the region, then in theory we could use the Lagrange to */
+ /* extrapolate beyond the end from points within.) */
for (lip = six; (lip + 3) < eix; lip++) {
double rwav[4]; /* Relative wavelength of these Lagrange points */
double den[4]; /* Denominator values for points */
@@ -8032,6 +8222,7 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
ihigh = rwav[1];
ilow = rwav[2];
+ /* Over just the central portion, if it overlaps the triangle. */
if ((k == 0 && ilow <= twidth && ihigh >= 0.0) /* Portion is +ve side */
|| (k == 1 && ilow <= 0.0 && ihigh >= -twidth)) { /* Portion is -ve side */
@@ -8186,6 +8377,8 @@ i1pro_code i1pro_compute_wav_filters(i1pro *p, int hr, int refl) {
#define DO_CCDNORMAVG /* [und ???] Normalise averages rather than per CCD bin */
/* (We relly on fine cal & white cal to fix it) */
+#define BOX_INTEGRATE /* [und] Integrate raw samples as if they were +/-0.5 boxes */
+ /* (This improves coeficient consistency a bit ?) */
#undef COMPUTE_DISPERSION /* Compute slit & optics dispersion from red laser data */
#ifdef NEVER
@@ -8219,7 +8412,7 @@ static void i1pro_debug_plot_mtx_coef(i1pro *p) {
do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
free_dvector(xx, -1, m->nraw-1);
- free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 5, -1, m->nraw-1);
}
#endif /* NEVER */
@@ -9540,7 +9733,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
w1 = i1pro_raw2wav(p, refl, (double)i - 0.5);
w2 = i1pro_raw2wav(p, refl, (double)i + 0.5);
-// printf("~1 CCD %d, w1 %f, wl %f, w2 %f\n",i,w1,wl,w2);
+// printf("~1 CCD %d, w1 %f, wl %f, w2 %f\n",i,w1,wl,w2);
/* For each filter */
for (j = 0; j < m->nwav[1]; j++) {
@@ -9554,6 +9747,7 @@ i1pro_code i1pro_create_hr(i1pro *p) {
if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
continue; /* Doesn't fall into this filter */
+#ifdef BOX_INTEGRATE
/* Integrate in 0.05 nm increments from filter shape */
/* using triangular integration. */
{
@@ -9582,6 +9776,9 @@ i1pro_code i1pro_create_hr(i1pro *p) {
lw = cw;
}
}
+#else
+ we = fabs(w2 - w1) * lanczos2(twidth, rwl);
+#endif
if (m->mtx_c[1][refl].nocoef[j] >= MXNOFC) {
a1logw(p->log, "i1pro: run out of high res filter space\n");
@@ -9943,7 +10140,7 @@ i1pro_code i1pro_set_scan_toll(i1pro *p, double toll_ratio) {
}
-/* Optics adjustment weights */
+/* Optical adjustment weights */
static double opt_adj_weights[21] = {
1.4944496665144658e-282, 2.0036175483913455e-070, 1.2554893022685038e+232,
2.3898157055642966e+190, 1.5697625128432372e-076, 6.6912978722191457e+281,
@@ -9954,7 +10151,8 @@ static double opt_adj_weights[21] = {
9.2709981544886391e+122, 3.7958270103353899e-153, 7.1366083837501666e-154
};
-/* Convert from spectral to XYZ, and transfer to the ipatch array */
+/* Convert from spectral to XYZ, and transfer to the ipatch array. */
+/* Apply XRGA conversion if needed */
i1pro_code i1pro_conv2XYZ(
i1pro *p,
ipatch *vals, /* Values to return */
@@ -10062,6 +10260,10 @@ i1pro_code i1pro_conv2XYZ(
}
conv->del(conv);
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, nvals, xcalstd_nonpol, m->target_calstd, m->native_calstd, clamp);
+
return I1PRO_OK;
}
@@ -11383,6 +11585,7 @@ i1pro_setmcmode(
}
/* Hmm. Give the instrument a little time to reconfigure itself. */
+ /* (Probably needs about 1msec, but err on the safe side) */
msec_sleep(10);
a1logd(p->log,2,"i1pro_setmcmode: done, ICOM err 0x%x (%d msec)\n",
@@ -11727,7 +11930,7 @@ i1pro2_triggermeasure(i1pro *p, int delay) {
i1proimp *m = (i1proimp *)p->m;
int rv = I1PRO_OK;
- a1logd(p->log,2,"i1pro2_triggermeasure: triggering Rev Emeasurement after %dmsec "
+ a1logd(p->log,2,"i1pro2_triggermeasure: triggering Rev E measurement after %dmsec "
"delay @ %d msec\n", delay, msec_time() - m->msec);
/* NOTE := would be better here to create thread once, and then trigger it */
@@ -12512,6 +12715,8 @@ static i1pro_code i1data_parse_eeprom(i1data *d, unsigned char *buf, unsigned in
i1pro *p = d->p;
int rv = I1PRO_OK;
int dir = 0x1000; /* Location of key directory */
+ int minkeys = 300; /* Expected minumum number of bytes for keys */
+ int maxkeys = 512; /* Expected maxumum number of bytes for keys */
int block_id; /* Block id */
int nokeys;
i1key key, off, nkey = 0, noff = 0;
@@ -12519,14 +12724,16 @@ static i1pro_code i1data_parse_eeprom(i1data *d, unsigned char *buf, unsigned in
unsigned char *bp;
int i;
- if (extra)
+ if (extra) {
dir = 0x2000; /* Directory is at half way in i1pro2 2nd table */
+ minkeys = 200; /* Hmm. Had a report that the i1Pro2 failed to parse */
+ }
- a1logd(p->log,3,"i1pro_parse_eeprom called with %d bytes\n",len);
+ a1logd(p->log,3,"i1pro_parse_eeprom called with %d bytes, table %d\n",len,extra);
/* Room for minimum number of keys ? */
- if ((dir + 300) > len)
- return I1PRO_DATA_KEY_COUNT;
+ if ((dir + minkeys) > len)
+ return I1PRO_DATA_KEY_COUNT_SMALL;
block_id = buf2ushort(buf + dir);
if ((extra == 0 && block_id != 1) /* Must be 1 for base data */
@@ -12534,12 +12741,15 @@ static i1pro_code i1data_parse_eeprom(i1data *d, unsigned char *buf, unsigned in
return I1PRO_DATA_KEY_CORRUPT;
nokeys = buf2ushort(buf + dir + 2); /* Bytes in key table */
- if (nokeys < 300 || nokeys > 512)
- return I1PRO_DATA_KEY_COUNT;
+ a1logd(p->log,3,"%d bytes for keys in EEProm table %d\n",nokeys, extra);
+ if (nokeys < minkeys)
+ return I1PRO_DATA_KEY_COUNT_SMALL;
+ if (nokeys > maxkeys)
+ return I1PRO_DATA_KEY_COUNT_LARGE;
nokeys = (nokeys - 4)/6; /* Number of 6 byte entries */
- a1logd(p->log,3,"%d key/values in EEProm table %d\n",nokeys, extra);
+ a1logd(p->log,3,"%d keys & values in EEProm table %d\n",nokeys, extra);
/* We need current and next value to figure data size out */
bp = buf + dir + 4;
diff --git a/spectro/i1pro_imp.h b/spectro/i1pro_imp.h
index 5a2cef2..582cc98 100644
--- a/spectro/i1pro_imp.h
+++ b/spectro/i1pro_imp.h
@@ -4,7 +4,9 @@
* Argyll Color Correction System
*
* Gretag i1Pro implementation defines
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 20/12/2006
*
@@ -15,6 +17,10 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/*
If you make use of the instrument driver code here, please note
that it is the author(s) of the code who take responsibility
@@ -182,6 +188,9 @@ struct _i1proimp {
int uv_en; /* NZ to do UV reflective measurement */
/* ~~ change this to uv_mode of none, uv, strip1, 2pass */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
double intclkp; /* Integration clock period (typically 68 usec) */
int subclkdiv; /* Sub clock divider ratio */
int subtmode; /* Reading 127 subtract mode (version 301 or greater) */
@@ -363,10 +372,11 @@ void del_i1proimp(i1pro *p);
#define I1PRO_DATA_KEYNOTFOUND 0x05 /* a key value wasn't found */
#define I1PRO_DATA_WRONGTYPE 0x06 /* a key is the wrong type */
#define I1PRO_DATA_KEY_CORRUPT 0x07 /* key table seems to be corrupted */
-#define I1PRO_DATA_KEY_COUNT 0x08 /* key table count is too big or small */
-#define I1PRO_DATA_KEY_UNKNOWN 0x09 /* unknown key type */
-#define I1PRO_DATA_KEY_MEMRANGE 0x0a /* key data is out of range of EEProm */
-#define I1PRO_DATA_KEY_ENDMARK 0x0b /* And end section marker was missing */
+#define I1PRO_DATA_KEY_COUNT_SMALL 0x08 /* key table count is too small */
+#define I1PRO_DATA_KEY_COUNT_LARGE 0x09 /* key table count is too big */
+#define I1PRO_DATA_KEY_UNKNOWN 0x0a /* unknown key type */
+#define I1PRO_DATA_KEY_MEMRANGE 0x0b /* key data is out of range of EEProm */
+#define I1PRO_DATA_KEY_ENDMARK 0x0c /* And end section marker was missing */
/* HW errors */
#define I1PRO_HW_HIGHPOWERFAIL 0x10 /* Switch to high power mode failed */
@@ -464,6 +474,7 @@ i1pro_code i1pro_imp_calibrate(
i1pro *p,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+ inst_calc_id_type *idtype, /* Condition identifier type */
char id[100] /* Condition identifier (ie. white reference ID) */
);
@@ -475,6 +486,12 @@ i1pro_code i1pro_imp_measure(
instClamping clamp /* Clamp XYZ/Lab to be +ve */
);
+/* Do a dummy reflective read, to fix Lamp Drift. */
+i1pro_code i1pro_imp_lamp_fix(
+ i1pro *p,
+ double seconds /* Number of seconds to turn lamp on for */
+);
+
/* Measure the emissive refresh rate */
i1pro_code i1pro_imp_meas_refrate(
i1pro *p,
@@ -1052,6 +1069,7 @@ i1pro2_getmeaschar(
#define I1PRO2_MMF_LAMP 0x0100 /* Use the Incandescent Lamp as the illuminant */
#define I1PRO2_MMF_UV_LED 0x0200 /* Use the Ultra Violet LED as the illuminant */
#define I1PRO2_MMF_WL_LED 0x0300 /* Use the Wavelength Reference LED as the illuminant */
+
//#define I1PRO2_MMF_HIGHGAIN 0x0000 /* Rev E mode has no high gain mode ? */
#define I1PRO2_MMF_SCAN 0x0001 /* Scan mode bit, else spot mode */
#define I1PRO2_MMF_RULER_START 0x0004 /* Start ruler tracking in scan mode */
@@ -1404,5 +1422,9 @@ struct _i1data {
/* Constructor. Construct from the EEprom contents */
extern i1data *new_i1data(i1proimp *m);
+#ifdef __cplusplus
+ }
+#endif
+
#define I1PRO_IMP
#endif /* I1PRO_IMP */
diff --git a/spectro/icoms.c b/spectro/icoms.c
index b69b72a..eadecc9 100644
--- a/spectro/icoms.c
+++ b/spectro/icoms.c
@@ -1,5 +1,5 @@
- /* General instrument + serial I/O support */
+/* General instrument + serial I/O support */
/*
* Argyll Color Correction System
@@ -71,29 +71,35 @@ static void icompath_del(icompath *p) {
free(p);
}
-/* Delete the last path */
+/* Delete the last combined path */
+/* (Assume this is before icompaths_make_dslists() has been called) */
static void icompaths_del_last_path(
icompaths *p
) {
- if (p->npaths == 0)
+ icom_dtix ix = dtix_combined;
+
+ if (p->ndpaths[ix] == 0)
return;
- icompath_del(p->paths[p->npaths-1]);
- p->paths[p->npaths-1] = NULL;
- p->npaths--;
+ icompath_del(p->dpaths[ix][p->ndpaths[ix]-1]);
+ p->dpaths[ix][p->ndpaths[ix]-1] = NULL;
+ p->ndpaths[ix]--;
}
-/* Return the last path */
+/* Return the last combined path */
+/* (Assume this is before icompaths_make_dslists() has been called) */
static icompath *icompaths_get_last_path(
icompaths *p
) {
- if (p->npaths == 0)
+ icom_dtix ix = dtix_combined;
+
+ if (p->ndpaths[ix] == 0)
return NULL;
- return p->paths[p->npaths-1];
+ return p->dpaths[ix][p->ndpaths[ix]-1];
}
-/* Return the path corresponding to the port number, or NULL if out of range */
+/* Return the instrument path corresponding to the port number, or NULL if out of range */
static icompath *icompaths_get_path(
icompaths *p,
int port /* Enumerated port number, 1..n */
@@ -103,80 +109,188 @@ static icompath *icompaths_get_path(
- if (port <= 0 || port > p->npaths)
+ if (port <= 0 || port > p->ndpaths[dtix_inst])
+ return NULL;
+
+ return p->dpaths[dtix_inst][port-1];
+}
+
+/* Return the device path corresponding to the port number, or NULL if out of range */
+static icompath *icompaths_get_path_sel(
+ icompaths *p,
+ icom_type dctype, /* Device type list */
+ int port /* Enumerated port number, 1..n */
+) {
+ /* Check it is an enumeration */
+ if (dctype != dtix_combined
+ && dctype != dtix_inst
+ && dctype != dtix_3dlut
+ && dctype != dtix_vtpg
+ && dctype != dtix_printer)
+ return NULL;
+
+ if (dctype == dtix_inst)
+ return icompaths_get_path(p, port);
+
+ if (port <= 0 || port > p->ndpaths[dctype])
return NULL;
- return p->paths[port-1];
+ return p->dpaths[dctype][port-1];
}
-static void icompaths_clear(icompaths *p) {
+/* Clear a single device paths list */
+static void icompaths_clear(icompaths *p, icom_dtix ix) {
- /* Free any old list */
- if (p != NULL && p->paths != NULL) {
+ if (p->dpaths[ix] != NULL) {
int i;
- for (i = 0; i < p->npaths; i++) {
- icompath_del(p->paths[i]);
+ /* If underlying owner of icompaths */
+ if (ix == dtix_combined) {
+ for (i = 0; i < p->ndpaths[ix]; i++) {
+ icompath_del(p->dpaths[ix][i]);
+ }
+ }
+ free(p->dpaths[ix]);
+ p->dpaths[ix] = NULL;
+ p->ndpaths[ix] = 0;
+
+ /* Clear instrument alias */
+ if (ix == dtix_inst) {
+ p->npaths = 0;
+ p->paths = NULL;
}
- free(p->paths);
- p->npaths = 0;
- p->paths = NULL;
}
}
-/* Add an empty new path. */
+/* Clear all device paths */
+static void icompaths_clear_all(icompaths *p) {
+
+ if (p == NULL)
+ return;
+
+ /* Free any old instrument list */
+ icompaths_clear(p, dtix_inst);
+ icompaths_clear(p, dtix_3dlut);
+ icompaths_clear(p, dtix_vtpg);
+ icompaths_clear(p, dtix_printer);
+ icompaths_clear(p, dtix_combined);
+}
+
+/* Add the give path to the given list. */
+/* If the path is NULL, allocat an empty */
+/* one and add it to the combined list */
/* Return icom error */
-static int icompaths_add_path(icompaths *p) {
- if (p->paths == NULL) {
- if ((p->paths = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL) {
+static int icompaths_add_path(icompaths *p, int ix, icompath *xp) {
+ if (xp == NULL)
+ ix = dtix_combined;
+ if (p->dpaths[ix] == NULL) {
+ if ((p->dpaths[ix] = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: calloc failed!\n");
return ICOM_SYS;
}
} else {
icompath **npaths;
- if ((npaths = (icompath **)realloc(p->paths,
- sizeof(icompath *) * (p->npaths + 2))) == NULL) {
+ if ((npaths = (icompath **)realloc(p->dpaths[ix],
+ sizeof(icompath *) * (p->ndpaths[ix] + 2))) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: realloc failed!\n");
return ICOM_SYS;
}
- p->paths = npaths;
- p->paths[p->npaths+1] = NULL;
+ p->dpaths[ix] = npaths;
+ p->dpaths[ix][p->ndpaths[ix]+1] = NULL;
}
- if ((p->paths[p->npaths] = calloc(sizeof(icompath), 1)) == NULL) {
- a1loge(p->log, ICOM_SYS, "icompaths: malloc failed!\n");
- return ICOM_SYS;
+ if (xp == NULL) {
+ if ((xp = calloc(sizeof(icompath), 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icompaths: malloc failed!\n");
+ return ICOM_SYS;
+ }
+ }
+ p->dpaths[ix][p->ndpaths[ix]] = xp;
+ p->ndpaths[ix]++;
+ p->dpaths[ix][p->ndpaths[ix]] = NULL;
+ return ICOM_OK;
+}
+
+/* Based on each icompath's dctype, create aliase lists for everything */
+/* on the combined path based on each device type. */
+/* (We are only called after clearing all lists) */
+int icompaths_make_dslists(icompaths *p) {
+ int rv, i;
+
+ for (i = 0; i < p->ndpaths[dtix_combined]; i++) {
+ icompath *xp = p->dpaths[dtix_combined][i];
+
+ if (xp == NULL)
+ break;
+
+ a1logd(g_log, 8, "icompaths_make_dslists '%s' dctype 0x%x\n",xp->name,xp->dctype);
+
+ if (xp->dctype & icomt_instrument) {
+ if ((rv = icompaths_add_path(p, dtix_inst, xp)) != ICOM_OK)
+ return rv;
+ }
+ if (xp->dctype & icomt_3dlut) {
+ if ((rv = icompaths_add_path(p, dtix_3dlut, xp)) != ICOM_OK)
+ return rv;
+ }
+ if (xp->dctype & icomt_vtpg) {
+ if ((rv = icompaths_add_path(p, dtix_vtpg, xp)) != ICOM_OK)
+ return rv;
+ }
+ if (xp->dctype & icomt_printer) {
+ if ((rv = icompaths_add_path(p, dtix_printer, xp)) != ICOM_OK)
+ return rv;
+ }
}
- p->npaths++;
- p->paths[p->npaths] = NULL;
+
+ /* Maintain backwards compatible instrument list alias */
+ p->npaths = p->ndpaths[dtix_inst];
+ p->paths = p->dpaths[dtix_inst];
+
return ICOM_OK;
}
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
-/* Add a serial path */
+/* Add a serial path. */
/* return icom error */
-static int icompaths_add_serial(icompaths *p, char *name, char *spath, icom_ser_attr sattr) {
+static int icompaths_add_serial(icompaths *p, char *name, char *spath, icom_type dctype) {
+ icom_dtix ix = dtix_combined;
+ icompath *xp;
int rv;
- if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ if ((rv = icompaths_add_path(p, ix, NULL)) != ICOM_OK)
return rv;
-
- if ((p->paths[p->npaths-1]->name = strdup(name)) == NULL) {
+
+ xp = p->dpaths[ix][p->ndpaths[ix]-1];
+
+ a1logd(g_log, 8, "icompaths_add_serial got '%s' dctype 0x%x\n",name,dctype);
+
+ /* Type of port, port attributes, device category */
+ xp->dctype |= icomt_cat_any; /* Assume any for now */
+ xp->dctype |= icomt_serial;
+ xp->dctype |= icomt_seriallike;
+ xp->dctype |= dctype;
+
+ if ((xp->name = strdup(name)) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
return ICOM_SYS;
}
- if ((p->paths[p->npaths-1]->spath = strdup(spath)) == NULL) {
+ if ((xp->spath = strdup(spath)) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
return ICOM_SYS;
}
- p->paths[p->npaths-1]->sattr = sattr;
+
+ a1logd(g_log, 8, "icompaths_add_serial returning '%s' dctype 0x%x\n",xp->name,xp->dctype);
return ICOM_OK;
}
-/* Modify a serial path to add the instrument type */
-int icompaths_set_serial_itype(icompath *p, instType itype) {
+/* Modify a serial path to add the device type */
+int icompaths_set_serial_itype(icompath *p, devType itype) {
char pname[400], *cp;
+ /* Convert device type to category */
+ p->dctype = (p->dctype & ~icomt_cat_mask) | inst_category(itype);
+
p->itype = itype;
/* Strip any existing description in brackets */
@@ -190,6 +304,9 @@ int icompaths_set_serial_itype(icompath *p, instType itype) {
return ICOM_SYS;
}
free(cp);
+
+ a1logd(g_log, 8, "icompaths_set_serial_itype '%s' returning dctype 0x%x\n",p->name,p->dctype);
+
return ICOM_OK;
}
@@ -197,60 +314,81 @@ int icompaths_set_serial_itype(icompath *p, instType itype) {
#ifdef ENABLE_USB
-/* Set an icompath details */
+/* Set an icompath details. */
/* return icom error */
static
int icompath_set_usb(a1log *log, icompath *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct usb_idevice *usbd, instType itype) {
+ int nep, struct usb_idevice *usbd, devType itype) {
int rv;
+
if ((p->name = strdup(name)) == NULL) {
a1loge(log, ICOM_SYS, "icompath: strdup failed!\n");
return ICOM_SYS;
}
+ a1logd(g_log, 8, "icompath_set_usb '%s' got dctype 0x%x\n",p->name,p->dctype);
+
+ p->dctype |= icomt_usb;
+ p->dctype = (p->dctype & ~icomt_cat_mask) | inst_category(itype);
+
p->nep = nep;
p->vid = vid;
p->pid = pid;
p->usbd = usbd;
p->itype = itype;
+ a1logd(g_log, 8, "icompath_set_usb '%s' returning dctype 0x%x\n",p->name,p->dctype);
+
return ICOM_OK;
}
/* Add a usb path. usbd is taken, others are copied. */
/* return icom error */
static int icompaths_add_usb(icompaths *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct usb_idevice *usbd, instType itype) {
+ int nep, struct usb_idevice *usbd, devType itype) {
+ icom_dtix ix = dtix_combined;
+ icompath *xp;
int rv;
- if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ if ((rv = icompaths_add_path(p, 0, NULL)) != ICOM_OK)
return rv;
- return icompath_set_usb(p->log, p->paths[p->npaths-1], name, vid, pid, nep, usbd, itype);
+ xp = p->dpaths[ix][p->ndpaths[ix]-1];
- return ICOM_OK;
+ return icompath_set_usb(p->log, xp, name, vid, pid, nep, usbd, itype);
}
/* Add an hid path. hidd is taken, others are copied. */
/* return icom error */
static int icompaths_add_hid(icompaths *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct hid_idevice *hidd, instType itype) {
+ int nep, struct hid_idevice *hidd, devType itype) {
+ icom_dtix ix = dtix_combined;
+ icompath *xp;
int rv;
- if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ if ((rv = icompaths_add_path(p, 0, NULL)) != ICOM_OK)
return rv;
- if ((p->paths[p->npaths-1]->name = strdup(name)) == NULL) {
+ xp = p->dpaths[ix][p->ndpaths[ix]-1];
+
+ a1logd(g_log, 8, "icompaths_add_hid '%s' got dctype 0x%x\n",xp->name,xp->dctype);
+
+ xp->dctype |= icomt_hid;
+ xp->dctype = (xp->dctype & ~icomt_cat_mask) | inst_category(itype);
+
+ if ((xp->name = strdup(name)) == NULL) {
a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
return ICOM_SYS;
}
- p->paths[p->npaths-1]->nep = nep;
- p->paths[p->npaths-1]->vid = vid;
- p->paths[p->npaths-1]->pid = pid;
- p->paths[p->npaths-1]->hidd = hidd;
- p->paths[p->npaths-1]->itype = itype;
+ xp->nep = nep;
+ xp->vid = vid;
+ xp->pid = pid;
+ xp->hidd = hidd;
+ xp->itype = itype;
+
+ a1logd(g_log, 8, "icompath_set_usb '%s' returning dctype 0x%x\n",xp->name,xp->dctype);
return ICOM_OK;
}
@@ -258,18 +396,115 @@ static int icompaths_add_hid(icompaths *p, char *name, unsigned int vid, unsigne
static void icompaths_del(icompaths *p) {
if (p != NULL) {
- icompaths_clear(p);
+ icompaths_clear_all(p);
p->log = del_a1log(p->log); /* Unreference it and set to NULL */
free(p);
}
}
-int icompaths_refresh_paths(icompaths *p); /* Defined in platform specific */
+/* Create and return a list of available serial ports or USB devices for this system. */
+/* We look at the registry key "HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM" */
+/* to determine serial ports, and use libusb to discover USB devices. */
+/* return icom error */
+int icompaths_refresh_paths_sel(icompaths *p, icom_type mask) {
+ int rv, usbend = 0;
+ int i, j;
+
+ a1logd(p->log, 7, "icoms_refresh_paths: called with mask = %d\n",mask);
+
+ /* Clear any existing device paths */
+ p->clear(p);
+
+#ifdef ENABLE_USB
+ if (mask & icomt_hid) {
+ a1logd(p->log, 6, "icoms_refresh_paths: looking for HID device\n");
+ if ((rv = hid_get_paths(p)) != ICOM_OK)
+ return rv;
+ }
+ if (mask & icomt_usb) {
+ a1logd(p->log, 6, "icoms_refresh_paths: looking for USB device\n");
+ if ((rv = usb_get_paths(p)) != ICOM_OK)
+ return rv;
+ }
+ usbend = p->ndpaths[dtix_combined];
+ a1logd(p->log, 6, "icoms_refresh_paths: now got %d paths\n",usbend);
+#endif /* ENABLE_USB */
+
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+
+ if (mask & (icomt_serial | icomt_fastserial | icomt_btserial)) {
+ a1logd(p->log, 6, "icoms_refresh_paths: looking for serial ports\n");
+ if ((rv = serial_get_paths(p, mask)) != ICOM_OK)
+ return rv;
+
+ }
+#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL */
+
+ /* Sort the COM keys so people don't get confused... */
+ /* Sort identified instruments ahead of unknown serial ports */
+ a1logd(p->log, 6, "icoms_refresh_paths: we now have %d devices and are about to sort them\n",p->ndpaths[dtix_combined]);
+
+ {
+ icompath **pl = p->dpaths[dtix_combined];
+ int np = p->ndpaths[dtix_combined];
+
+ for (i = usbend; i < (np-1); i++) {
+ for (j = i+1; j < np; j++) {
+ if ((pl[i]->itype == instUnknown && pl[j]->itype != instUnknown)
+ || (((pl[i]->itype == instUnknown && pl[j]->itype == instUnknown)
+ || (pl[i]->itype != instUnknown && pl[j]->itype != instUnknown))
+ && strcmp(pl[i]->name, pl[j]->name) > 0)) {
+ icompath *tt = pl[i];
+ pl[i] = pl[j];
+ pl[j] = tt;
+ }
+ }
+ }
+ }
+
+ /* Create the device specific lists */
+ if ((rv = icompaths_make_dslists(p)) != ICOM_OK) {
+ a1logd(p->log, 1, "icoms_refresh_paths: icompaths_make_dslists failed with %d\n",rv);
+ return rv;
+ }
+
+ a1logd(p->log, 8, "icoms_refresh_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
+
+ return ICOM_OK;
+}
+
+/* (In implementation specific) */
+int serial_is_open(icoms *p);
+void serial_close_port(icoms *p);
+
+/* Close the port */
+static void icoms_close_port(icoms *p) {
+ if (p->is_open) {
+#ifdef ENABLE_USB
+ if (p->usbd) {
+ usb_close_port(p);
+ } else if (p->hidd) {
+ hid_close_port(p);
+ }
+#endif
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ if (serial_is_open(p)) {
+ serial_close_port(p);
+ }
+#endif /* ENABLE_SERIAL */
+ p->is_open = 0;
+ }
+}
+
+int icompaths_refresh_paths(icompaths *p) {
+ return icompaths_refresh_paths_sel(p, icomt_instrument | icomt_portattr_all);
+}
/* Allocate an icom paths and set it to the list of available devices */
+/* that match the icom_type mask. */
/* Return NULL on error */
-icompaths *new_icompaths(a1log *log) {
+icompaths *new_icompaths_sel(a1log *log, icom_type mask) {
icompaths *p;
if ((p = (icompaths *)calloc(sizeof(icompaths), 1)) == NULL) {
a1loge(log, ICOM_SYS, "new_icompath: calloc failed!\n");
@@ -278,11 +513,14 @@ icompaths *new_icompaths(a1log *log) {
p->log = new_a1log_d(log);
- p->clear = icompaths_clear;
+ p->clear = icompaths_clear_all;
p->refresh = icompaths_refresh_paths;
- p->del_last_path = icompaths_del_last_path;
- p->get_last_path = icompaths_get_last_path;
+ p->refresh_sel = icompaths_refresh_paths_sel;
p->get_path = icompaths_get_path;
+ p->get_path_sel = icompaths_get_path_sel;
+ p->del = icompaths_del;
+
+ /* ====== internal implementation ======= */
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
p->add_serial = icompaths_add_serial;
#endif /* ENABLE_SERIAL */
@@ -290,9 +528,11 @@ icompaths *new_icompaths(a1log *log) {
p->add_usb = icompaths_add_usb;
p->add_hid = icompaths_add_hid;
#endif /* ENABLE_USB */
- p->del = icompaths_del;
+ p->del_last_path = icompaths_del_last_path;
+ p->get_last_path = icompaths_get_last_path;
+ /* ====================================== */
- if (icompaths_refresh_paths(p)) {
+ if (icompaths_refresh_paths_sel(p, mask)) {
a1loge(log, ICOM_SYS, "new_icompaths: icompaths_refresh_paths failed!\n");
free(p);
return NULL;
@@ -301,6 +541,12 @@ icompaths *new_icompaths(a1log *log) {
return p;
}
+/* Allocate an icom paths and set it to the list of available instruments */
+/* Return NULL on error */
+icompaths *new_icompaths(a1log *log) {
+ return new_icompaths_sel(log, icomt_instrument | icomt_portattr_all);
+}
+
/* ----------------------------------------------------- */
@@ -321,7 +567,6 @@ static int icom_copy_path_to_icom(icoms *p, icompath *pp) {
a1loge(p->log, ICOM_SYS, "copy_path_to_icom: malloc spath failed\n");
return ICOM_SYS;
}
- p->sattr = pp->sattr;
} else {
p->spath = NULL;
}
@@ -335,24 +580,36 @@ static int icom_copy_path_to_icom(icoms *p, icompath *pp) {
if ((rv = hid_copy_hid_idevice(p, pp)) != ICOM_OK)
return rv;
#endif
+ p->dctype = pp->dctype;
p->itype = pp->itype;
+ a1logd(g_log, 8, "icom_copy_path_to_icom '%s' returning dctype 0x%x\n",p->name,p->dctype);
+
return ICOM_OK;
}
-/* Return the port type */
-static icom_type icoms_port_type(
+/* Return the device category */
+/* (Returns bit flags) */
+static icom_type icoms_cat_type(
icoms *p
) {
+ return p->dctype & icomt_cat_mask;
+}
-#ifdef ENABLE_USB
- if (p->hidd != NULL)
- return icomt_hid;
- if (p->usbd != NULL)
- return icomt_usb;
-#endif
+/* Return the communication port type */
+/* (Can use equality tests on return value) */
+static icom_type icoms_port_type(
+icoms *p
+) {
+ return p->dctype & icomt_port_mask;
+}
- return icomt_serial;
+/* Return the communication port attributes */
+/* (Returns bit flags) */
+static icom_type icoms_port_attr(
+icoms *p
+) {
+ return p->dctype & icomt_attr_mask;
}
/* ----------------------------------------------------- */
@@ -365,10 +622,10 @@ icoms *p
# include "icoms_ux.c"
#endif
-/* write and read convenience function */
+/* write and read convenience function with read flush */
/* return icom error */
static int
-icoms_write_read(
+icoms_write_read_ex(
icoms *p,
char *wbuf, /* Write puffer */
int nwch, /* if > 0, number of characters to write, else nul terminated */
@@ -377,27 +634,33 @@ int bsize, /* Buffer size */
int *bread, /* Bytes read (not including forced '\000') */
char *tc, /* Terminating characers, NULL for none or char count mode */
int ntc, /* Number of terminating characters needed, or char count needed */
-double tout /* Timeout for write and then read (i.e. max = 2 x tout) */
+double tout, /* Timeout for write and then read (i.e. max = 2 x tout) */
+int frbw /* nz to Flush Read Before Write */
) {
int rv = ICOM_OK;
a1logd(p->log, 8, "icoms_write_read: called\n");
if (p->write == NULL || p->read == NULL) { /* Neither serial nor USB ? */
- a1loge(p->log, ICOM_NOTS, "icoms_write_read: Neither serial nor USB device!\n");
+ a1loge(p->log, ICOM_NOTS, "icoms_write_read: No write and read functions set!\n");
return ICOM_NOTS;
}
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- /* Flush any stray chars if serial ?? */
- if (0 && p->usbd == NULL && p->hidd == NULL) {
- char tbuf[100];
+ /* Flush any stray chars if serial */
+ if (frbw && (p->dctype & icomt_serial)) {
+ char tbuf[500];
int debug = p->log->debug;
+ int bread;
if (debug < 8)
p->log->debug = 0;
- for (; rv == ICOM_OK;) /* Until we get a timeout */
- rv = p->read(p, tbuf, 100, NULL, NULL, 100, 0.01);
+ for (;;) {
+ bread = 0;
+ p->read(p, tbuf, 500, &bread, NULL, 500, 0.02);
+ if (bread == 0)
+ break;
+ }
p->log->debug = debug;
rv = ICOM_OK;
}
@@ -420,6 +683,23 @@ double tout /* Timeout for write and then read (i.e. max = 2 x tout) */
return rv;
}
+/* write and read convenience function */
+/* return icom error */
+static int
+icoms_write_read(
+icoms *p,
+char *wbuf, /* Write puffer */
+int nwch, /* if > 0, number of characters to write, else nul terminated */
+char *rbuf, /* Read buffer */
+int bsize, /* Buffer size */
+int *bread, /* Bytes read (not including forced '\000') */
+char *tc, /* Terminating characers, NULL for none or char count mode */
+int ntc, /* Number of terminating characters needed, or char count needed */
+double tout /* Timeout for write and then read (i.e. max = 2 x tout) */
+) {
+ return icoms_write_read_ex(p, wbuf, nwch, rbuf, bsize, bread, tc, ntc, tout, 0);
+}
+
/* Optional callback to client from device */
/* Default implementation is a NOOP */
static int icoms_interrupt(icoms *p,
@@ -428,6 +708,29 @@ static int icoms_interrupt(icoms *p,
return ICOM_OK;
}
+/* Destroy ourselves */
+static void
+icoms_del(icoms *p) {
+ a1logd(p->log, 8, "icoms_del: called\n");
+ if (p->is_open) {
+ a1logd(p->log, 8, "icoms_del: closing port\n");
+ p->close_port(p);
+ }
+#ifdef ENABLE_USB
+ usb_del_usb(p);
+ hid_del_hid(p);
+#endif
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ if (p->spath != NULL)
+ free(p->spath);
+#endif
+ p->log = del_a1log(p->log);
+ if (p->name != NULL)
+ free(p->name);
+ p->log = del_a1log(p->log); /* unref */
+ free (p);
+}
+
/* icoms Constructor */
/* Return NULL on error */
icoms *new_icoms(
@@ -435,6 +738,9 @@ icoms *new_icoms(
a1log *log /* log to take reference from, NULL for default */
) {
icoms *p;
+
+ a1logd(log, 2, "new_icoms '%s' itype '%s' dctype 0x%x\n",ipath->name,inst_sname(ipath->itype),ipath->dctype);
+
if ((p = (icoms *)calloc(sizeof(icoms), 1)) == NULL) {
a1loge(log, ICOM_SYS, "new_icoms: calloc failed!\n");
return NULL;
@@ -475,14 +781,19 @@ icoms *new_icoms(
p->close_port = icoms_close_port;
+ p->dev_cat = icoms_cat_type;
p->port_type = icoms_port_type;
+ p->port_attr = icoms_port_attr;
+
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ p->set_ser_port_ex = icoms_set_ser_port_ex;
p->set_ser_port = icoms_set_ser_port;
#endif /* ENABLE_SERIAL */
p->write = NULL; /* Serial open or set_methods will set */
p->read = NULL;
p->write_read = icoms_write_read;
+ p->write_read_ex = icoms_write_read_ex;
p->interrupt = icoms_interrupt;
p->del = icoms_del;
@@ -512,9 +823,9 @@ void good_beep() {
/* Emit a "bad" double beep */
void bad_beep() {
- /* 0msec delay, 800Hz for 200 msec */
+ /* 0 msec delay, 800Hz for 200 msec */
msec_beep(0, 800, 200);
- /* 500msec delay, 800Hz for 200 msec */
+ /* 350 msec delay, 800Hz for 200 msec */
msec_beep(350, 800, 200);
}
diff --git a/spectro/icoms.h b/spectro/icoms.h
index 2a282f0..be36cac 100644
--- a/spectro/icoms.h
+++ b/spectro/icoms.h
@@ -1,7 +1,7 @@
#ifndef ICOMS_H
- /* An abstracted instrument serial and USB communication class. */
+/* An abstracted instrument serial and USB communication class. */
/*
* Argyll Color Correction System
@@ -30,7 +30,7 @@
#include <windows.h>
#endif
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
#include <IOKit/usb/IOUSBLib.h>
#endif
@@ -40,6 +40,76 @@
#undef QUIET_MEMCHECKERS /* #define to memset coms read buffers before reading */
+/* USB open/handling/buf workaround flags */
+typedef enum {
+ icomuf_none = 0x0000,
+ icomuf_detach = 0x0001, /* Attempt to detach from system driver */
+ icomuf_no_open_clear = 0x0002, /* Don't send a clear_halt after opening the port */
+ icomuf_reset_before_close = 0x0004, /* Reset port before closing it */
+ /* ??? Could change to reset before open ??? */
+ icomuf_resetep_before_read = 0x0008 /* Do a usb_resetep before each ep read */
+} icomuflags;
+
+typedef enum {
+ icomt_unknown = 0x0000,
+
+ /* Category of device */
+ icomt_instrument = 0x010000, /* Color measurement instrument (default) */
+ icomt_3dlut = 0x020000, /* A 3D cLUT box */
+ icomt_vtpg = 0x040000, /* A video test patern generator box */
+ icomt_printer = 0x080000, /* A printing device */
+
+ icomt_cat_any = 0x0f0000, /* Could be any device category */
+ icomt_cat_mask = 0xff0000, /* Mask for device category */
+
+ /* Type of underlying communication port */
+ /* (fastserio driver will have icomt_serial and icomt_usb set) */
+ icomt_serial = 0x000001, /* Serial port (i.e. has baud rate etc.) */
+ icomt_usb = 0x000002, /* USB port */
+ icomt_hid = 0x000004, /* HID USB port */
+ icomt_bt = 0x000008, /* Bluetooth (non-serial) */
+
+ icomt_port_mask = 0x0000ff, /* Mask for port type */
+
+ /* Attributes */
+ icomt_fastserial = 0x000100, /* Fast Serial (i.e. USB, fastserio, Bluetooth) */
+ icomt_btserial = 0x000200, /* Bluetooth serial port */
+ icomt_seriallike = 0x000400, /* Uses serial message methods, but */
+ /* may not be actual icomt_serial. */
+
+ icomt_attr_mask = 0x00ff00, /* Mask for port attributes */
+
+ icomt_portattr_mask = icomt_port_mask | icomt_attr_mask,
+
+ icomt_portattr_all = icomt_portattr_mask /* Scan for all port types */
+
+
+} icom_type;
+
+/* Status bits/return values */
+#define ICOM_OK 0x000000 /* No error */
+
+#define ICOM_NOTS 0x001000 /* Not supported */
+#define ICOM_SIZE 0x002000 /* Request/response size exceeded limits */
+#define ICOM_TO 0x004000 /* Timed out, but there may be bytes read/written */
+#define ICOM_SHORT 0x008000 /* No timeout but number of bytes wasn't read/written */
+#define ICOM_CANC 0x010000 /* Was cancelled */
+#define ICOM_SYS 0x020000 /* System error (ie. malloc, system call fail) */
+#define ICOM_VER 0x040000 /* Version error - need up to date kernel driver */
+
+#define ICOM_USBR 0x000100 /* Unspecified USB read error */
+#define ICOM_USBW 0x000200 /* Unspecified USB write error */
+#define ICOM_SERR 0x000400 /* Unspecified Serial read error */
+#define ICOM_SERW 0x000800 /* Unspecified Serial write error */
+
+#define ICOM_XRE 0x000040 /* Xmit shift reg empty */
+#define ICOM_XHE 0x000020 /* Xmit hold reg empty */
+#define ICOM_BRK 0x000010 /* Break detected */
+#define ICOM_FER 0x000008 /* Framing error */
+#define ICOM_PER 0x000004 /* Parity error */
+#define ICOM_OER 0x000002 /* Overun error */
+#define ICOM_DRY 0x000001 /* Recv data ready */
+
typedef struct _icompath icompath;
typedef struct _icompaths icompaths;
typedef struct _icoms icoms;
@@ -56,7 +126,7 @@ typedef struct {
int packetsize; /* The max packet size */
int type; /* 2 = bulk, 3 = interrupt */
int interface; /* interface number */
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
int pipe; /* pipe number (1..N, OS X only) */
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
@@ -72,27 +142,17 @@ typedef struct {
#endif /* ENABLE_USB */
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
-
-/* Attributes of the serial port */
-typedef enum {
- icom_normal = 0x0000, /* Normal serial port */
- icom_fast = 0x0001, /* Fast port */
- icom_bt = 0x0002 /* Bluetooth serial port */
-} icom_ser_attr;
-
-#endif
-
/* - - - - - - - - - - - - - - - - - - - - */
/* Store information about a possible instrument communication path */
/* (Note a path doesn't have a reference to icompaths or its' log) */
-struct _icompath{
- instType itype; /* Type of instrument if known */
+struct _icompath {
+ devType itype; /* Type of device if known */
char *name; /* instance description */
+
+ icom_type dctype; /* Device and com. type */
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
char *spath; /* Serial device path */
- icom_ser_attr sattr; /* Virtual serial port that can be identified quickly */
#endif
#ifdef ENABLE_USB
int nep; /* Number of end points */
@@ -104,56 +164,93 @@ struct _icompath{
extern icompath icomFakeDevice; /* Declare fake device */
+/* Device type specific list index */
+typedef enum {
+ dtix_combined = 0, /* Combined list */
+ dtix_inst, /* Instrument */
+ dtix_3dlut,
+ dtix_vtpg,
+ dtix_printer,
+
+ dtix_number /* Number of entries */
+} icom_dtix;
+
/* The available instrument communication paths */
struct _icompaths {
- int npaths; /* Number of paths */
- icompath **paths; /* Paths if any */
a1log *log; /* Verbose, debuge & error logging */
- /* Re-populate the available instrument list */
+ /* Combined and device category specific path lists (read only). */
+ /* Paths may appear on more than one, if they are multi-function, */
+ /* or the category can't be determined without opening them. */
+ /* (dpaths[dtix_combined] is the owner of the icompath, */
+ /* and all the others are only populated after discovery.) */
+ icompath **dpaths[dtix_number]; /* Device paths if any */
+ int ndpaths[dtix_number]; /* Number of device paths */
+
+ /* Alias of dpaths[dtix_inst] for backwards compatibility, */
+ /* only set after discovery. */
+ icompath **paths; /* Device instrument if any */
+ int npaths; /* Number of instrument paths */
+
+ /* Re-discover and populate the available instrument list */
/* return icom error */
int (*refresh)(struct _icompaths *p);
+ /* Same as above, but just scan for selected types of devices and/or port types */
+ int (*refresh_sel)(struct _icompaths *p, icom_type mask);
+
+ /* Return the instrument path corresponding to the port number, or NULL if out of range */
+ icompath *(*get_path)(
+ struct _icompaths *p,
+ int port); /* Enumerated port number, 1..n */
+#define FAKE_DEVICE_PORT -98 /* Fake display & instrument */
+#define DEMO_DEVICE_PORT -99 /* Fake Demo instrument */
+
+ /* Return the device path corresponding to the port number, or NULL if out of range */
+ icompath *(*get_path_sel)(
+ struct _icompaths *p,
+ icom_type dctype, /* Device type list */
+ int port); /* Enumerated port number, 1..n */
+
+ /* Clear all the device paths */
+ void (*clear)(struct _icompaths *p);
+
+ /* We're done */
+ void (*del)(struct _icompaths *p);
+
+ /* ====== internal implementation ======= */
+
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- /* Add a serial path. path is copied. Return icom error */
- int (*add_serial)(struct _icompaths *p, char *name, char *spath, icom_ser_attr sattr);
+ /* Add a serial path to combined. path is copied. Return icom error */
+ int (*add_serial)(struct _icompaths *p, char *name, char *spath, icom_type dctype);
#endif /* ENABLE_SERIAL */
#ifdef ENABLE_USB
- /* Add a usb path. usbd is taken, others are copied. Return icom error */
+ /* Add a usb path to combined. usbd is taken, others are copied. Return icom error */
int (*add_usb)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct usb_idevice *usbd, instType itype);
+ int nep, struct usb_idevice *usbd, devType itype);
- /* Add an hid path. hidd is taken, others are copied. Return icom error */
+ /* Add an hid path to combined. hidd is taken, others are copied. Return icom error */
int (*add_hid)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
- int nep, struct hid_idevice *hidd, instType itype);
+ int nep, struct hid_idevice *hidd, devType itype);
#endif /* ENABLE_USB */
- /* Delete the last path */
+ /* Delete the last combined path */
void (*del_last_path)(struct _icompaths *p);
- /* Return the last path */
+ /* Return the last combined path */
icompath *(*get_last_path)(struct _icompaths *p);
- /* Return the path corresponding to the port number, or NULL if out of range */
- icompath *(*get_path)(
- struct _icompaths *p,
- int port); /* Enumerated port number, 1..n */
-#define FAKE_DEVICE_PORT -98 /* Fake display & instrument */
-#define DEMO_DEVICE_PORT -99 /* Fake Demo instrument */
-
- /* Clear all the paths */
- void (*clear)(struct _icompaths *p);
-
- /* We're done */
- void (*del)(struct _icompaths *p);
-
};
/* Allocate an icom paths and set it to the list of available devices */
+/* Use g_log as argument for default logging. */
/* Return NULL on error */
icompaths *new_icompaths(a1log *log);
+/* Same as above, but just scan for selected types of devices and/or port types */
+icompaths *new_icompaths_sel(a1log *log, icom_type mask);
+
/* - - - - - - - - - - - */
/* Serial related stuff */
@@ -161,7 +258,7 @@ icompaths *new_icompaths(a1log *log);
/* Flow control */
typedef enum {
fc_nc = 0, /* not configured/default */
- fc_none,
+ fc_None,
fc_XonXOff,
fc_Hardware, /* RTS CTS flow control */
fc_HardwareDTR /* DTR DSR flow control */
@@ -211,47 +308,6 @@ typedef enum {
length_8
} word_length;
-/* USB open/handling/buf workaround flags */
-typedef enum {
- icomuf_none = 0x0000,
- icomuf_detach = 0x0001, /* Attempt to detach from system driver */
- icomuf_no_open_clear = 0x0001, /* Don't send a clear_halt after opening the port */
- icomuf_reset_before_close = 0x0004, /* Reset port before closing it */
- icomuf_resetep_before_read = 0x0008 /* Do a usb_resetep before each ep read */
-} icomuflags;
-
-/* Type of port driver */
-typedef enum {
- icomt_serial, /* Serial port */
- icomt_usbserial, /* Serial port using fastserio.c driver */
- icomt_usb, /* USB port */
- icomt_hid /* HID (USB) port */
-} icom_type;
-
-/* Status bits/return values */
-#define ICOM_OK 0x000000 /* No error */
-
-#define ICOM_NOTS 0x001000 /* Not supported */
-#define ICOM_SIZE 0x002000 /* Request/response size exceeded limits */
-#define ICOM_TO 0x004000 /* Timed out, but there may be bytes read/written */
-#define ICOM_SHORT 0x008000 /* No timeout but number of bytes wasn't read/written */
-#define ICOM_CANC 0x010000 /* Was cancelled */
-#define ICOM_SYS 0x020000 /* System error (ie. malloc, system call fail) */
-#define ICOM_VER 0x040000 /* Version error - need up to date kernel driver */
-
-#define ICOM_USBR 0x000100 /* Unspecified USB read error */
-#define ICOM_USBW 0x000200 /* Unspecified USB write error */
-#define ICOM_SERR 0x000400 /* Unspecified Serial read error */
-#define ICOM_SERW 0x000800 /* Unspecified Serial write error */
-
-#define ICOM_XRE 0x000040 /* Xmit shift reg empty */
-#define ICOM_XHE 0x000020 /* Xmit hold reg empty */
-#define ICOM_BRK 0x000010 /* Break detected */
-#define ICOM_FER 0x000008 /* Framing error */
-#define ICOM_PER 0x000004 /* Parity error */
-#define ICOM_OER 0x000002 /* Overun error */
-#define ICOM_DRY 0x000001 /* Recv data ready */
-
/* Interrupt callback type */
typedef enum {
icomi_data_available /* Data is available to be read */
@@ -270,8 +326,10 @@ struct _icoms {
/* Private: */
/* Copy of some of icompath contents: */
+ icom_type dctype; /* Device cat. and com. type */
+ devType itype; /* Type of device if known */
+
char *name; /* Device description */
- instType itype; /* Type of instrument if known */
int is_open; /* Flag, NZ if this port is open */
@@ -287,11 +345,9 @@ struct _icoms {
#if defined (NT)
HANDLE phandle; /* NT handle */
#endif
-#if defined (UNIX) || defined(__APPLE__)
+#if defined (UNIX)
int fd; /* Unix file descriptor */
#endif
- icom_ser_attr sattr; /* Serial port attributes, such as being fast */
-
flow_control fc;
baud_rate br;
parity py;
@@ -339,10 +395,31 @@ struct _icoms {
/* Public: */
- /* Return the port type */
+ /* Return the device category */
+ /* (Returns bit flags) */
+ icom_type (*dev_cat)(struct _icoms *p);
+
+ /* Return the communication port type */
+ /* (Can use equality tests on return value for normal ports, */
+ /* or bit flag for fastserio USB/serial port) */
icom_type (*port_type)(struct _icoms *p);
+ /* Return the communication port attributes */
+ /* (Returns bit flags) */
+ icom_type (*port_attr)(struct _icoms *p);
+
#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+ /* Select the serial communications port and characteristics - extended version */
+ /* return icom error */
+ int (*set_ser_port_ex)(
+ struct _icoms *p,
+ flow_control fc, /* Flow control */
+ baud_rate baud,
+ parity parity,
+ stop_bits stop_bits,
+ word_length word_length,
+ int delayms); /* Delay in ms after open */
+
/* Select the serial communications port and characteristics */
/* return icom error */
int (*set_ser_port)(
@@ -414,6 +491,20 @@ struct _icoms {
int ntc, /* Number of any terminating characters needed, or char count needed */
double tout); /* Timeout in seconds */
+ /* "Serial" write and read with read flush */
+ /* return icom error */
+ int (*write_read_ex)(
+ struct _icoms *p,
+ char *wbuf, /* Write puffer */
+ int nwch, /* if > 0, number of characters to write, else nul terminated */
+ char *rbuf, /* Read buffer */
+ int bsize, /* Buffer size. Make this larger than chars required! */
+ int *bread, /* Bytes read (not including forced '\000') */
+ char *tc, /* Terminating characers, NULL for none or char count mode */
+ int ntc, /* Number of any terminating characters needed, or char count needed */
+ double tout, /* Timeout in seconds */
+ int frbw); /* nz to Flush Read Before Write */
+
/* For a USB device, do a control message */
/* return icom error */
int (*usb_control)(struct _icoms *p,
@@ -504,6 +595,16 @@ char *icoms_fix(char *s);
/* Convert a limited binary buffer to a list of hex */
char *icoms_tohex(unsigned char *s, int len);
+/* Implementation declarations */
+
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+
+int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout);
+int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
+ char *tc, int ntc, double tout);
+
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/spectro/icoms_nt.c b/spectro/icoms_nt.c
index 14258e9..b9e0d0c 100644
--- a/spectro/icoms_nt.c
+++ b/spectro/icoms_nt.c
@@ -1,5 +1,5 @@
-
- /* Windows NT serial I/O class */
+
+/* Windows NT serial I/O class */
/*
* Argyll Color Correction System
@@ -14,195 +14,171 @@
* see the License2.txt file for licencing details.
*/
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+
#include <conio.h>
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
instType fast_ser_inst_type(icoms *p, int tryhard, void *, void *);
-#endif /* ENABLE_SERIAL */
-
-/* Create and return a list of available serial ports or USB instruments for this system. */
-/* We look at the registry key "HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM" */
-/* to determine serial ports, and use libusb to discover USB instruments. */
-/* Create and return a list of available serial ports or USB instruments for this system */
-/* return icom error */
-int icompaths_refresh_paths(icompaths *p) {
- int rv, usbend = 0;
- int i, j;
+
+/* Add paths to serial connected device. */
+/* Return an icom error */
+int serial_get_paths(icompaths *p, icom_type mask) {
+ int i;
LONG stat;
HKEY sch; /* Serial coms handle */
- a1logd(p->log, 8, "icoms_get_paths: called\n");
+ a1logd(p->log, 7, "serial_get_paths: called with mask = %d\n",mask);
- /* Clear any existing paths */
- p->clear(p);
-
-#ifdef ENABLE_USB
- if ((rv = hid_get_paths(p)) != ICOM_OK)
- return rv;
- if ((rv = usb_get_paths(p)) != ICOM_OK)
- return rv;
-#endif /* ENABLE_USB */
- usbend = p->npaths;
-
- a1logd(p->log, 6, "icoms_get_paths: got %d paths, looking up the registry for serial ports\n",p->npaths);
-
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
// (Beware KEY_WOW64_64KEY ?)
#define MXKSIZE 500
#define MXVSIZE 300
- /* Look in the registry for serial ports */
- if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM",
- 0, KEY_READ, &sch)) != ERROR_SUCCESS) {
- a1logd(p->log, 1, "icoms_get_paths: There don't appear to be any serial ports\n");
- return ICOM_OK; /* Maybe they have USB ports */
- }
+ if (mask & (icomt_serial | icomt_fastserial | icomt_btserial)) {
- /* Look at all the values in this key */
- a1logd(p->log, 8, "icoms_get_paths: looking through all the values in the SERIALCOMM key\n");
-
- for (i = 0; ; i++) {
- char valname[MXKSIZE], *vp;
- DWORD vnsize = MXKSIZE;
- DWORD vtype;
- char value[MXVSIZE];
- DWORD vsize = MXVSIZE;
- icom_ser_attr sattr = icom_normal;
-
- stat = RegEnumValue(
- sch, /* handle to key to enumerate */
- i, /* index of subkey to enumerate */
- valname, /* address of buffer for value name */
- &vnsize, /* address for size of value name buffer */
- NULL, /* reserved */
- &vtype, /* Address of value type */
- value, /* Address of value buffer */
- &vsize /* Address of value buffer size */
- );
- if (stat == ERROR_NO_MORE_ITEMS) {
- a1logd(p->log, 8, "icoms_get_paths: got ERROR_NO_MORE_ITEMS\n");
- break;
- }
- if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */
- || stat != ERROR_SUCCESS) {
- a1logw(p->log, "icoms_get_paths: RegEnumValue failed with %d\n",stat);
- break;
+ a1logd(p->log, 6, "serial_get_paths: looking up the registry for serial ports\n");
+ /* Look in the registry for serial ports */
+ if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM",
+ 0, KEY_READ, &sch)) != ERROR_SUCCESS) {
+ a1logd(p->log, 1, "serial_get_paths: There don't appear to be any serial ports\n");
+ return ICOM_OK;
}
- valname[MXKSIZE-1] = '\000';
- value[MXVSIZE-1] = '\000';
- if (vtype != REG_SZ) {
- a1logw(p->log, "icoms_get_paths: RegEnumValue didn't return stringz type\n");
- continue;
- }
+ /* Look at all the values in this key */
+ a1logd(p->log, 8, "serial_get_paths: looking through all the values in the SERIALCOMM key\n");
+
+ for (i = 0; ; i++) {
+ char valname[MXKSIZE], *vp;
+ DWORD vnsize = MXKSIZE;
+ DWORD vtype;
+ char value[MXVSIZE];
+ DWORD vsize = MXVSIZE;
+ icom_type dctype = icomt_unknown;
+
+ stat = RegEnumValue(
+ sch, /* handle to key to enumerate */
+ i, /* index of subkey to enumerate */
+ valname, /* address of buffer for value name */
+ &vnsize, /* address for size of value name buffer */
+ NULL, /* reserved */
+ &vtype, /* Address of value type */
+ value, /* Address of value buffer */
+ &vsize /* Address of value buffer size */
+ );
+ if (stat == ERROR_NO_MORE_ITEMS) {
+ a1logd(p->log, 8, "serial_get_paths: got ERROR_NO_MORE_ITEMS\n");
+ break;
+ }
+ if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */
+ || stat != ERROR_SUCCESS) {
+ a1logw(p->log, "serial_get_paths: RegEnumValue failed with %d\n",stat);
+ break;
+ }
+ valname[MXKSIZE-1] = '\000';
+ value[MXVSIZE-1] = '\000';
- if ((vp = strrchr(valname, '\\')) == NULL)
- vp = valname;
- else
- vp++;
+ if (vtype != REG_SZ) {
+ a1logw(p->log, "serial_get_paths: RegEnumValue didn't return stringz type\n");
+ continue;
+ }
- /* See if it looks like a fast port */
- if (strncmp(vp, "VCP", 3) == 0) { /* Virtual */
- sattr |= icom_fast;
- }
+ if ((vp = strrchr(valname, '\\')) == NULL)
+ vp = valname;
+ else
+ vp++;
- if (strncmp(vp, "BtPort", 6) == 0) { /* Blue tooth */
- sattr |= icom_fast;
- sattr |= icom_bt;
- }
+ a1logd(p->log, 8, "serial_get_paths: checking '%s'\n",vp);
+
+ /* See if it looks like a fast port */
+ if (strncmp(vp, "VCP", 3) == 0) { /* Virtual */
+ dctype |= icomt_fastserial;
+ }
+
+ if (strncmp(vp, "USBSER", 6) == 0) { /* USB Serial port */
+ dctype |= icomt_fastserial;
+ }
+
+ if (strncmp(vp, "BtPort", 6) == 0 /* Blue tooth */
+ || strncmp(vp, "BthModem", 8) == 0) {
+ dctype |= icomt_fastserial;
+ dctype |= icomt_btserial;
+ }
#ifndef ENABLE_SERIAL
- if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */
+ if (dctype & icomt_fastserial) { /* Only add fast ports if !ENABLE_SERIAL */
#endif
- /* Add the port to the list */
- p->add_serial(p, value, value, sattr);
- a1logd(p->log, 8, "icoms_get_paths: Added path '%s' sattr 0x%x\n",value,sattr);
+ if (((mask & icomt_serial) && !(dctype & icomt_fastserial))
+ || ((mask & icomt_fastserial) && (dctype & icomt_fastserial)
+ && !(dctype & icomt_btserial))
+ || ((mask & icomt_btserial) && (dctype & icomt_btserial))) {
+
+ // ~~ would be nice to add better description, similar
+ // to that of device manager, i.e. "Prolific USB-to-SerialBridge (COM6)"
+ /* Add the port to the list */
+ p->add_serial(p, value, value, dctype);
+ a1logd(p->log, 8, "serial_get_paths: Added '%s' path '%s' dctype 0x%x\n",vp, value,dctype);
+ }
#ifndef ENABLE_SERIAL
- }
+ }
#endif
- /* If fast, try and identify it */
- if (sattr & icom_fast) {
- icompath *path;
- icoms *icom;
- if ((path = p->get_last_path(p)) != NULL
- && (icom = new_icoms(path, p->log)) != NULL) {
- instType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
- if (itype != instUnknown)
- icompaths_set_serial_itype(path, itype);
- icom->del(icom);
+ /* If fast, try and identify it */
+ if (dctype & icomt_fastserial) {
+ icompath *path;
+ icoms *icom;
+ if ((path = p->get_last_path(p)) != NULL
+ && (icom = new_icoms(path, p->log)) != NULL) {
+ devType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
+ if (itype != instUnknown)
+ icompaths_set_serial_itype(path, itype); /* And set category */
+ icom->del(icom);
+ }
+ a1logd(p->log, 8, "serial_get_paths: Identified '%s' dctype 0x%x\n",inst_sname(path->itype),path->dctype);
}
}
- }
- if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) {
- a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat);
- }
-#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL */
-
- /* Sort the COM keys so people don't get confused... */
- /* Sort identified instruments ahead of unknown serial ports */
- a1logd(p->log, 6, "icoms_get_paths: we now have %d entries and are about to sort them\n",p->npaths);
- for (i = usbend; i < (p->npaths-1); i++) {
- for (j = i+1; j < p->npaths; j++) {
- if ((p->paths[i]->itype == instUnknown && p->paths[j]->itype != instUnknown)
- || (((p->paths[i]->itype == instUnknown && p->paths[j]->itype == instUnknown)
- || (p->paths[i]->itype != instUnknown && p->paths[j]->itype != instUnknown))
- && strcmp(p->paths[i]->name, p->paths[j]->name) > 0)) {
- icompath *tt = p->paths[i];
- p->paths[i] = p->paths[j];
- p->paths[j] = tt;
- }
+ if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) {
+ a1logw(p->log, "serial_get_paths: RegCloseKey failed with %d\n",stat);
}
}
- a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
-
return ICOM_OK;
}
+/* -------------------------------------------------------------------- */
-/* Close the port */
-static void icoms_close_port(icoms *p) {
- if (p->is_open) {
-#ifdef ENABLE_USB
- if (p->usbd) {
- usb_close_port(p);
- } else if (p->hidd) {
- hid_close_port(p);
- }
-#endif
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- if (p->phandle != NULL) {
- CloseHandle(p->phandle);
- }
-#endif /* ENABLE_SERIAL */
- p->is_open = 0;
- }
+/* Is the serial port actually open ? */
+int serial_is_open(icoms *p) {
+ return p->phandle != NULL;
}
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+/* Close the serial port */
+void serial_close_port(icoms *p) {
+
+ if (p->is_open && p->phandle != NULL) {
+ CloseHandle(p->phandle);
+ p->phandle = NULL;
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
+ }
+}
-static int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout);
-static int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
- char *tc, int ntc, double tout);
+/* -------------------------------------------------------------------- */
#ifndef CBR_921600
# define CBR_921600 921600
#endif
-/* Set the serial port characteristics */
+/* Set the serial port characteristics - extended */
/* This always re-opens the port */
/* return an icom error */
static int
-icoms_set_ser_port(
+icoms_set_ser_port_ex(
icoms *p,
flow_control fc,
baud_rate baud,
parity parity,
stop_bits stop,
-word_length word)
-{
+word_length word,
+int delayms) { /* Delay after open in msec */
a1logd(p->log, 8, "icoms_set_ser_port: About to set port characteristics:\n"
" Port name = %s\n"
@@ -211,10 +187,13 @@ word_length word)
" Parity = %d\n"
" Stop bits = %d\n"
" Word length = %d\n"
- ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word);
+ " Open delay = %d ms\n"
+ ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word, delayms);
- if (p->is_open)
+ if (p->is_open) {
+ a1logd(p->log, 8, "icoms_set_ser_port: closing port '%s'\n",p->name);
p->close_port(p);
+ }
if (p->port_type(p) == icomt_serial) {
DCB dcb;
@@ -234,7 +213,7 @@ word_length word)
/* Make sure the port is open */
if (!p->is_open) {
- char buf[50]; /* Temporary for COM device path */
+ char buf[100]; /* Temporary for COM device path */
a1logd(p->log, 8, "icoms_set_ser_port: about to open serial port '%s'\n",p->spath);
@@ -253,11 +232,18 @@ word_length word)
a1logd(p->log, 1, "icoms_set_ser_port: open port '%s' failed with LastError %d\n",buf,GetLastError());
return ICOM_SYS;
}
+
+ if (delayms < 160) /* Seems to need at least 80 msec with many drivers */
+ delayms = 160;
+
+ msec_sleep(delayms); /* For Bluetooth */
+
p->is_open = 1;
}
if (GetCommState(p->phandle, &dcb) == FALSE) {
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: reading state '%s' failed with LastError %d\n",p->spath,GetLastError());
return ICOM_SYS;
}
@@ -274,14 +260,17 @@ word_length word)
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_ENABLE; /* Turn RTS on during connection */
-// dcb.fAbortOnError = TRUE; // Hmm. Stuffs up FTDI. Is it needed ?
- dcb.fAbortOnError = FALSE;
+ dcb.fAbortOnError = FALSE; /* Hmm. TRUE Stuffs up FTDI. Is it needed ? */
switch (p->fc) {
case fc_nc:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal flow control %d\n",p->fc);
return ICOM_SYS;
+ case fc_None:
+ /* Use no flow control */
+ break;
case fc_XonXOff:
/* Use Xon/Xoff bi-directional flow control */
dcb.fOutX = TRUE;
@@ -307,6 +296,7 @@ word_length word)
switch (p->py) {
case parity_nc:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal parity setting %d\n",p->py);
return ICOM_SYS;
case parity_none:
@@ -328,6 +318,7 @@ word_length word)
switch (p->sb) {
case stop_nc:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal stop bits %d\n",p->sb);
return ICOM_SYS;
case stop_1:
@@ -341,6 +332,7 @@ word_length word)
switch (p->wl) {
case length_nc:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal word length %d\n",p->wl);
return ICOM_SYS;
case length_5:
@@ -399,20 +391,24 @@ word_length word)
break;
default:
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal baud rate! (0x%x)\n",p->br);
return ICOM_SYS;
}
- PurgeComm(p->phandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
+ PurgeComm(p->phandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
if (!SetCommState(p->phandle, &dcb)) {
CloseHandle(p->phandle);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: SetCommState failed with LastError %d\n",
GetLastError());
return ICOM_SYS;
}
- PurgeComm(p->phandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
+ PurgeComm(p->phandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
+
+ msec_sleep(50); /* Improves reliability of USB<->Serial converters */
p->write = icoms_ser_write;
p->read = icoms_ser_read;
@@ -423,6 +419,22 @@ word_length word)
return ICOM_OK;
}
+/* Set the serial port characteristics */
+/* This always re-opens the port */
+/* return an icom error */
+static int
+icoms_set_ser_port(
+icoms *p,
+flow_control fc,
+baud_rate baud,
+parity parity,
+stop_bits stop,
+word_length word)
+{
+ return icoms_set_ser_port_ex(p, fc, baud, parity, stop, word, 0);
+}
+
+
/* ---------------------------------------------------------------------------------*/
/* Serial write, read */
@@ -430,7 +442,7 @@ word_length word)
/* Data will be written up to the terminating nul */
/* Return relevant error status bits */
/* Set the icoms lserr value */
-static int
+int
icoms_ser_write(
icoms *p,
char *wbuf, /* null terminated unless nwch > 0 */
@@ -519,7 +531,7 @@ double tout)
/* Read characters into the buffer */
/* Return string will be terminated with a nul */
-static int
+int
icoms_ser_read(
icoms *p,
char *rbuf, /* Buffer to store characters read */
@@ -645,30 +657,5 @@ double tout /* Time out in seconds */
return p->lserr;
}
-#endif /* ENABLE_SERIAL */
-/* ---------------------------------------------------------------------------------*/
-
-
-/* Destroy ourselves */
-static void
-icoms_del(icoms *p) {
- a1logd(p->log, 8, "icoms_del: called\n");
- if (p->is_open) {
- a1logd(p->log, 8, "icoms_del: closing port\n");
- p->close_port(p);
- }
-#ifdef ENABLE_USB
- usb_del_usb(p);
- hid_del_hid(p);
-#endif
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- if (p->spath != NULL)
- free(p->spath);
-#endif
- p->log = del_a1log(p->log);
- if (p->name != NULL)
- free(p->name);
- p->log = del_a1log(p->log); /* unref */
- free (p);
-}
+#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL*/
diff --git a/spectro/icoms_ux.c b/spectro/icoms_ux.c
index 7fb7359..9e79d7f 100644
--- a/spectro/icoms_ux.c
+++ b/spectro/icoms_ux.c
@@ -1,5 +1,5 @@
- /* Unix icoms and serial I/O class */
+/* Unix icoms and serial I/O class */
/*
* Argyll Color Correction System
@@ -18,6 +18,8 @@
TTBD:
*/
+#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+
#include <sys/types.h> /* Include sys/select.h ? */
#include <sys/stat.h>
#include <fcntl.h>
@@ -27,62 +29,50 @@
/* select() defined, but not poll(), so emulate poll() */
#if defined(FD_CLR) && !defined(POLLIN)
-#include "pollem.h"
-#define poll_x pollem
+# include "pollem.h"
+# define poll_x pollem
#else
-#include <sys/poll.h> /* Else assume poll() is native */
-#define poll_x poll
+# include <sys/poll.h> /* Else assume poll() is native */
+# define poll_x poll
#endif
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
//#include <stdbool.h>
-#include <sys/sysctl.h>
-#include <sys/param.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <IOKit/IOKitLib.h>
-#include <IOKit/serial/IOSerialKeys.h>
-#include <IOKit/IOBSD.h>
-#include <mach/mach_init.h>
-#include <mach/task_policy.h>
-#endif /* __APPLE__ */
-
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
-instType fast_ser_inst_type(icoms *p, int tryhard, void *, void *);
-#endif /* ENABLE_SERIAL */
+# include <sys/sysctl.h>
+# include <sys/param.h>
+# include <CoreFoundation/CoreFoundation.h>
+# include <IOKit/IOKitLib.h>
+# include <IOKit/serial/IOSerialKeys.h>
+# include <IOKit/IOBSD.h>
+# include <mach/mach_init.h>
+# include <mach/task_policy.h>
+#endif /* UNIX_APPLE */
-/* Create and return a list of available serial ports or USB instruments for this system */
-/* return icom error */
-int icompaths_refresh_paths(icompaths *p) {
- int rv, usbend = 0;
- int i,j;
- a1logd(p->log, 8, "icoms_get_paths: called\n");
+instType fast_ser_inst_type(icoms *p, int tryhard, void *, void *);
- /* Clear any existing paths */
- p->clear(p);
+/* Add paths to serial connected device. */
+/* Return an icom error */
+int serial_get_paths(icompaths *p, icom_type mask) {
+ int rv;
-#ifdef ENABLE_USB
- if ((rv = hid_get_paths(p)) != ICOM_OK)
- return rv;
- if ((rv = usb_get_paths(p)) != ICOM_OK)
- return rv;
-#endif /* ENABLE_USB */
- usbend = p->npaths;
+ a1logd(p->log, 7, "serial_get_paths: called with mask %d\n",mask);
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
/* Search the OSX registry for serial ports */
- {
+ if (mask & (icomt_serial | icomt_fastserial | icomt_btserial)) {
kern_return_t kstat;
mach_port_t mp; /* Master IO port */
CFMutableDictionaryRef sdict; /* Serial Port dictionary */
io_iterator_t mit; /* Matching itterator */
io_object_t ioob; /* Serial object found */
+ a1logd(p->log, 6, "serial_get_paths: looking up serial ports services\n");
+
/* Get dictionary of serial ports */
if ((sdict = IOServiceMatching(kIOSerialBSDServiceValue)) == NULL) {
a1loge(p->log, ICOM_SYS, "IOServiceMatching returned a NULL dictionary\n");
- return ICOM_OK;
+ return ICOM_OK; /* Hmm. There are no serial ports ? */
}
/* Set value to match to RS232 type serial */
@@ -98,7 +88,7 @@ int icompaths_refresh_paths(icompaths *p) {
/* Find all the matching serial ports */
for (;;) {
char pname[200];
- icom_ser_attr sattr = icom_normal;
+ icom_type dctype = icomt_unknown;
CFTypeRef dfp; /* Device file path */
@@ -114,36 +104,50 @@ int icompaths_refresh_paths(icompaths *p) {
if (!CFStringGetCString(dfp, pname, 100, kCFStringEncodingASCII))
goto continue2;
- /* Ignore infra red port or Bluetooth, or any other noise */
+ a1logd(p->log, 8, "serial_get_paths: checking '%s'\n",pname);
+
+ /* Ignore infra red port or any other noise */
if (strstr(pname, "IrDA") != NULL
|| strstr(pname, "Dialup") != NULL
- || strstr(pname, "Bluetooth") != NULL)
+ || strstr(pname, "PDA-Sync") != NULL)
goto continue2;
/* Would be nice to identify FTDI serial ports more specifically ? */
if (strstr(pname, "usbserial") != NULL)
- sattr |= icom_fast;
+ dctype |= icomt_fastserial;
+
+ if (strstr(pname, "Bluetooth") != NULL
+ || strstr(pname, "JETI") != NULL) {
+ dctype |= icomt_fastserial;
+ dctype |= icomt_btserial;
+ }
#ifndef ENABLE_SERIAL
- if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */
+ if (dctype & icomt_fastserial) { /* Only add fast ports if !ENABLE_SERIAL */
#endif
- /* Add the port to the list */
- p->add_serial(p, pname, pname, sattr);
- a1logd(p->log, 8, "icoms_get_paths: Added path '%s' attr 0x%x\n",pname, sattr);
+ if (((mask & icomt_serial) && !(dctype & icomt_fastserial))
+ || ((mask & icomt_fastserial) && (dctype & icomt_fastserial)
+ && !(dctype & icomt_btserial))
+ || ((mask & icomt_btserial) && (dctype & icomt_btserial))) {
+ /* Add the port to the list */
+ p->add_serial(p, pname, pname, dctype);
+ a1logd(p->log, 8, "serial_get_paths: Added path '%s' dctype 0x%x\n",pname, dctype);
+ }
#ifndef ENABLE_SERIAL
}
#endif
/* If fast, try and identify it */
- if (sattr & icom_fast) {
+ if (dctype & icomt_fastserial) {
icompath *path;
icoms *icom;
if ((path = p->get_last_path(p)) != NULL
&& (icom = new_icoms(path, p->log)) != NULL) {
instType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
if (itype != instUnknown)
- icompaths_set_serial_itype(path, itype);
+ icompaths_set_serial_itype(path, itype); /* And set category */
icom->del(icom);
}
+ a1logd(p->log, 8, "serial_get_paths: Identified '%s' dctype 0x%x\n",inst_sname(path->itype),path->dctype);
}
continue2:
CFRelease(dfp);
@@ -152,8 +156,9 @@ int icompaths_refresh_paths(icompaths *p) {
}
IOObjectRelease(mit); /* Release the itterator */
}
-#else
- /* Other UNIX like systems */
+
+#else /* Other UNIX like systems */
+
/* Many are crude and list every available device name, whether */
/* it's usable or not. Do any UNIX systems have a mechanism for listing */
/* serial ports ?? */
@@ -203,12 +208,16 @@ int icompaths_refresh_paths(icompaths *p) {
*/
/* Search for devices that match the pattern /dev/ttyS[0-9]* and /dev/ttyUSB* */
- /* We will assume that ttyUSB* ports includes FTDI ports */
- {
+ /* We will assume that ttyUSB* ports includes FTDI ports. */
+ /* Bluetooth ports are named ttyHS* or rfcomm* ?? */
+
+ if (mask & (icomt_serial | icomt_fastserial | icomt_bt)) {
DIR *dd;
struct dirent *de;
char *dirn = "/dev/";
+ a1logd(p->log, 6, "serial_get_paths: looking up serial port devices\n");
+
if ((dd = opendir(dirn)) == NULL) {
a1loge(p->log, ICOM_SYS, "failed to open directory \"%s\"\n",dirn);
return ICOM_OK;
@@ -217,10 +226,13 @@ int icompaths_refresh_paths(icompaths *p) {
for (;;) {
int fd;
char *dpath;
- icom_ser_attr sattr = icom_normal;
+ icom_type dctype = icomt_unknown;
- if ((de = readdir(dd)) == NULL)
+ if ((de = readdir(dd)) == NULL) {
break;
+ }
+
+ a1logd(p->log, 8, "serial_get_paths: checking '%s'\n",de->d_name);
if (!(
#if defined(__FreeBSD__) || defined(__OpenBSD__)
@@ -231,27 +243,32 @@ int icompaths_refresh_paths(icompaths *p) {
/* Presumably Linux.. */
( strncmp(de->d_name, "ttyS", 4) == 0
&& de->d_name[4] >= '0' && de->d_name[4] <= '9')
- || ( strncmp(de->d_name, "ttyUSB", 5) == 0)
+ || ( strncmp(de->d_name, "ttyUSB", 6) == 0)
+ || ( strncmp(de->d_name, "ttyHS", 5) == 0)
+ || ( strncmp(de->d_name, "rfcomm", 6) == 0)
#endif
))
continue;
if ((dpath = (char *)malloc(strlen(dirn) + strlen(de->d_name) + 1)) == NULL) {
closedir(dd);
- a1loge(p->log, ICOM_SYS, "icompaths_refresh_paths() malloc failed!\n");
+ a1loge(p->log, ICOM_SYS, "icompaths_refresh_paths_sel() malloc failed!\n");
return ICOM_SYS;
}
strcpy(dpath, dirn);
strcat(dpath, de->d_name);
/* See if the serial port is real */
- if (strncmp(de->d_name, "ttyUSB", 5) != 0) {
+ if (strncmp(de->d_name, "ttyUSB", 6) != 0
+ && strncmp(de->d_name, "ttyHS", 5) != 0
+ && strncmp(de->d_name, "rfcomm", 6) != 0) {
/* Hmm. This is probably a bad idea - it can upset other */
/* programs that use the serial ports ? */
if ((fd = open(dpath, O_RDONLY | O_NOCTTY | O_NONBLOCK)) < 0) {
- a1logd(p->log, 8, "icoms_get_paths: failed to open serial \"%s\" - not real\n",dpath);
+ a1logd(p->log, 8, "serial_get_paths: failed to open serial \"%s\" r/o - not real\n",dpath);
free(dpath);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
continue;
}
/* On linux we could do a
@@ -267,94 +284,83 @@ int icompaths_refresh_paths(icompaths *p) {
*/
close(fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
+ a1logd(p->log, 8, "serial_get_paths: open'd serial \"%s\" r/o - assume real\n",dpath);
}
- a1logd(p->log, 8, "icoms_get_paths: open'd serial \"%s\" - assume real\n",dpath);
- if (strncmp(de->d_name, "ttyUSB", 5) == 0)
- sattr |= icom_fast;
+ if (strncmp(de->d_name, "ttyUSB", 6) == 0
+ || strncmp(de->d_name, "ttyHS", 5) == 0
+ || strncmp(de->d_name, "rfcomm", 6) == 0)
+ dctype |= icomt_fastserial;
+
+ if (strncmp(de->d_name, "rfcomm", 6) == 0) {
+ dctype |= icomt_fastserial;
+ dctype |= icomt_btserial;
+ }
#ifndef ENABLE_SERIAL
- if (sattr & icom_fast) { /* Only add fast ports if !ENABLE_SERIAL */
+ if (dctype & icomt_fastserial) { /* Only add fast ports if !ENABLE_SERIAL */
#endif
- /* Add the path to the list */
- p->add_serial(p, dpath, dpath, 0);
- a1logd(p->log, 8, "icoms_get_paths: Added path '%s' attr 0x%x\n",dpath,sattr);
+ if (((mask & icomt_serial) && !(dctype & icomt_fastserial))
+ || ((mask & icomt_fastserial) && (dctype & icomt_fastserial)
+ && !(dctype & icomt_btserial))
+ || ((mask & icomt_btserial) && (dctype & icomt_btserial))) {
+ /* Add the port to the list */
+ p->add_serial(p, dpath, dpath, dctype);
+ a1logd(p->log, 8, "serial_get_paths: Added path '%s' dctype 0x%x\n",dpath, dctype);
+ }
#ifndef ENABLE_SERIAL
}
#endif
free(dpath);
/* If fast, try and identify it */
- if (sattr & icom_fast) {
+ if (dctype & icomt_fastserial) {
icompath *path;
icoms *icom;
if ((path = p->get_last_path(p)) != NULL
&& (icom = new_icoms(path, p->log)) != NULL) {
instType itype = fast_ser_inst_type(icom, 0, NULL, NULL);
if (itype != instUnknown)
- icompaths_set_serial_itype(path, itype);
+ icompaths_set_serial_itype(path, itype); /* And set category */
icom->del(icom);
}
+ a1logd(p->log, 8, "serial_get_paths: Identified '%s' dctype 0x%x\n",inst_sname(path->itype),path->dctype);
}
}
closedir(dd);
}
-#endif /* ! __APPLE__ */
-#endif /* ENABLE_SERIAL */
-
- /* Sort the serial /dev keys so people don't get confused... */
- /* Sort identified instruments ahead of unknown serial ports */
- for (i = usbend; i < (p->npaths-1); i++) {
- for (j = i+1; j < p->npaths; j++) {
- if ((p->paths[i]->itype == instUnknown && p->paths[j]->itype != instUnknown)
- || (((p->paths[i]->itype == instUnknown && p->paths[j]->itype == instUnknown)
- || (p->paths[i]->itype != instUnknown && p->paths[j]->itype != instUnknown))
- && strcmp(p->paths[i]->name, p->paths[j]->name) > 0)) {
- icompath *tt = p->paths[i];
- p->paths[i] = p->paths[j];
- p->paths[j] = tt;
- }
- }
- }
+#endif /* ! UNIX_APPLE */
+
return ICOM_OK;
}
/* -------------------------------------------------------------------- */
-/* Close the port */
-static void icoms_close_port(icoms *p) {
- if (p->is_open) {
-#ifdef ENABLE_USB
- if (p->usbd) {
- usb_close_port(p);
- } else if (p->hidd) {
- hid_close_port(p);
- }
-#endif
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- if (p->fd != -1) {
- close(p->fd);
- p->fd = -1;
- }
-#endif /* ENABLE_SERIAL */
- p->is_open = 0;
- }
+/* Is the serial port actually open ? */
+int serial_is_open(icoms *p) {
+ return p->fd != -1;
}
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
+/* Close the serial port */
+void serial_close_port(icoms *p) {
-static int icoms_ser_write(icoms *p, char *wbuf, int nwch, double tout);
-static int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
- char *tc, int ntc, double tout);
+ if (p->is_open && p->fd != -1) {
+ close(p->fd);
+ p->fd = -1;
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
+ }
+}
+/* -------------------------------------------------------------------- */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
# ifndef IOSSIOSPEED
# define IOSSIOSPEED _IOW('T', 2, speed_t)
# endif
#endif
-#if defined(__APPLE__) || defined(__OpenBSD__)
+#if defined(UNIX_APPLE) || defined(__OpenBSD__)
# ifndef B921600
# define B921600 921600
# endif
@@ -364,14 +370,14 @@ static int icoms_ser_read(icoms *p, char *rbuf, int bsize, int *bread,
/* This always re-opens the port */
/* return icom error */
static int
-icoms_set_ser_port(
+icoms_set_ser_port_ex(
icoms *p,
flow_control fc,
baud_rate baud,
parity parity,
stop_bits stop,
-word_length word
-) {
+word_length word,
+int delayms) { /* Delay after open in msec */
int rv;
struct termios tio;
speed_t speed = 0;
@@ -379,15 +385,18 @@ word_length word
a1logd(p->log, 8, "icoms_set_ser_port: About to set port characteristics:\n"
" Port name = %s\n"
" Flow control = %d\n"
- " Baud Rate = %d\n"
+ " Baud Rate = %s\n"
" Parity = %d\n"
" Stop bits = %d\n"
" Word length = %d\n"
- ,p->name ,fc ,baud ,parity ,stop ,word);
+ " Open delay = %d ms\n"
+ ,p->name ,fc ,baud_rate_to_str(baud) ,parity ,stop ,word, delayms);
- if (p->is_open) /* Close it and re-open it */
+ if (p->is_open) { /* Close it and re-open it */
+ a1logd(p->log, 8, "icoms_set_ser_port: closing port\n");
p->close_port(p);
+ }
if (p->port_type(p) == icomt_serial) {
@@ -410,10 +419,52 @@ word_length word
a1logd(p->log, 8, "icoms_set_ser_port: about to open serial port '%s'\n",p->spath);
if ((p->fd = open(p->spath, O_RDWR | O_NOCTTY )) < 0) {
- a1logd(p->log, 1, "icoms_set_ser_port: open port '%s' failed with %d (%s)\n",p->spath,p->fd,strerror(errno));
+ a1logd(p->log, 1, "icoms_set_ser_port: open port '%s' r/w failed with %d (%s)\n",p->spath,p->fd,strerror(errno));
+
+ if (delayms < 160) /* Seems to need at least 80 msec for many drivers */
+ delayms = 160;
+
+ msec_sleep(delayms); /* For Bluetooth */
+
+#ifdef NEVER /* See what supplementary groups we are a member of */
+ {
+ int j, ngroups = 16;
+ gid_t *groups = (gid_t *)malloc (ngroups * sizeof(gid_t));
+ struct passwd *pw = getpwuid(getuid());
+
+ if (groups == NULL) {
+ a1logd(p->log, 0, "icoms_set_ser_port: malloc of sgroups failed\n");
+ goto fail;
+ }
+ if (pw == NULL) {
+ a1logd(p->log, 0, "icoms_set_ser_port: getpwuid failed\n");
+ goto fail;
+ }
+
+ if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) < 0) {
+ groups = realloc(groups, ngroups * sizeof(gid_t));
+ if (groups == NULL) {
+ a1logd(p->log, 0, "icoms_set_ser_port: realloc of sgroups failed\n");
+ goto fail;
+ }
+ getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+ }
+ a1logd(p->log, 0, "icoms_set_ser_port: ngroups = %d\n", ngroups);
+ for (j = 0; j < ngroups; j++) {
+ struct group *gr = getgrgid(groups[j]);
+ if (gr != NULL)
+ a1logd(p->log, 0, "icoms_set_ser_port: %d: gid %d\n", j,groups[j]);
+ else
+ a1logd(p->log, 0, "icoms_set_ser_port: %d: gid %d (%s)\n", j,groups[j],gr->gr_name);
+ }
+ fail:;
+ }
+#endif
return ICOM_SYS;
}
+
/* O_NONBLOCK O_SYNC */
+
p->is_open = 1;
}
@@ -448,6 +499,7 @@ word_length word
switch (p->fc) {
case fc_nc:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal flow control %d\n",p->fc);
return ICOM_SYS;
case fc_XonXOff:
@@ -459,7 +511,7 @@ word_length word
break;
case fc_Hardware:
/* Use RTS/CTS bi-directional flow control */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
tio.c_cflag |= CCTS_OFLOW;
tio.c_cflag |= CRTS_IFLOW;
#else
@@ -468,7 +520,7 @@ word_length word
break;
case fc_HardwareDTR:
/* Use DTR/DSR bi-directional flow control */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
tio.c_cflag |= CDSR_OFLOW;
tio.c_cflag |= CDTR_IFLOW;
#else
@@ -484,6 +536,7 @@ word_length word
switch (p->py) {
case parity_nc:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal parity setting %d\n",p->py);
return ICOM_SYS;
break;
@@ -504,6 +557,7 @@ word_length word
switch (p->sb) {
case stop_nc:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal stop bits %d\n",p->sb);
return ICOM_SYS;
case stop_1:
@@ -516,6 +570,7 @@ word_length word
switch (p->wl) {
case length_nc:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal word length %d\n",p->wl);
return ICOM_SYS;
case length_5:
@@ -572,6 +627,7 @@ word_length word
break;
default:
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal baud rate! (0x%x)\n",p->br);
return ICOM_SYS;
}
@@ -589,11 +645,13 @@ word_length word
#endif
if ((rv = cfsetispeed(&tio, speed)) < 0) {
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: cfsetispeed failed with '%s'\n", strerror(errno));
return ICOM_SYS;
}
if ((rv = cfsetospeed(&tio, speed)) < 0) {
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: cfsetospeed failed with '%s'\n", strerror(errno));
return ICOM_SYS;
}
@@ -601,11 +659,13 @@ word_length word
/* Make change immediately */
if ((rv = tcsetattr(p->fd, TCSANOW, &tio)) < 0) {
close(p->fd);
+ msec_sleep(100); /* Improves reliability of USB<->Serial converters */
a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: tcsetattr failed with '%s'\n", strerror(errno));
return ICOM_SYS;
}
tcflush(p->fd, TCIOFLUSH); /* Discard any current in/out data */
+ msec_sleep(50); /* Improves reliability of USB<->Serial converters */
p->write = icoms_ser_write;
p->read = icoms_ser_read;
@@ -616,6 +676,29 @@ word_length word
return ICOM_OK;
}
+/* Set the serial port characteristics */
+/* This always re-opens the port */
+/* return an icom error */
+static int
+icoms_set_ser_port(
+icoms *p,
+flow_control fc,
+baud_rate baud,
+parity parity,
+stop_bits stop,
+word_length word)
+{
+ return icoms_set_ser_port_ex(p, fc, baud, parity, stop, word, 0);
+}
+
+/* ------------------------------ */
+/* Could add read flush function, to discard all read data using
+
+ tcflush(fd, TCIFLUSH);
+
+*/
+
+
/* ---------------------------------------------------------------------------------*/
/* Serial write/read */
@@ -623,7 +706,7 @@ word_length word
/* Data will be written up to the terminating nul */
/* Return relevant error status bits */
/* Set the icoms lserr value */
-static int
+int
icoms_ser_write(
icoms *p,
char *wbuf, /* null terminated unless nwch > 0 */
@@ -699,6 +782,8 @@ double tout
retrv |= ICOM_TO;
}
+// tcdrain(p->fd);
+
a1logd(p->log, 8, "icoms_ser_write: took %d msec, returning ICOM err 0x%x\n",etime - stime,retrv);
p->lserr = retrv;
return p->lserr;
@@ -707,7 +792,7 @@ double tout
/* Read characters into the buffer */
/* Return string will be terminated with a nul */
/* return icom error */
-static int
+int
icoms_ser_read(
icoms *p,
char *rbuf, /* Buffer to store characters read */
@@ -826,30 +911,5 @@ double tout /* Time out in seconds */
return p->lserr;
}
-#endif /* ENABLE_SERIAL */
-
-/* ---------------------------------------------------------------------------------*/
-
-/* Destroy ourselves */
-static void
-icoms_del(icoms *p) {
- a1logd(p->log, 8, "icoms_del: called\n");
- if (p->is_open) {
- a1logd(p->log, 8, "icoms_del: closing port\n");
- p->close_port(p);
- }
-#ifdef ENABLE_USB
- usb_del_usb(p);
- hid_del_hid(p);
-#endif
-#if defined(ENABLE_SERIAL) || defined(ENABLE_FAST_SERIAL)
- if (p->spath != NULL)
- free(p->spath);
-#endif
- p->log = del_a1log(p->log);
- if (p->name != NULL)
- free(p->name);
- p->log = del_a1log(p->log);
- free (p);
-}
+#endif /* ENABLE_SERIAL || ENABLE_FAST_SERIAL*/
diff --git a/spectro/illumread.c b/spectro/illumread.c
index 381f6b6..58569e3 100644
--- a/spectro/illumread.c
+++ b/spectro/illumread.c
@@ -393,7 +393,7 @@ int main(int argc, char *argv[])
if (na == NULL) usage(NULL);
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -431,17 +431,17 @@ int main(int argc, char *argv[])
/* Special debug */
strcpy(tnp, "_i.sp");
- if (read_xspect(&i_sp, tname) == 0) {
+ if (read_xspect(&i_sp, NULL, tname) == 0) {
rd_i = 1;
printf("(Found '%s' file and loaded it)\n",tname);
}
strcpy(tnp, "_r.sp");
- if (read_xspect(&r_sp, tname) == 0) {
+ if (read_xspect(&r_sp, NULL, tname) == 0) {
rd_r = 1;
printf("(Found '%s' file and loaded it)\n",tname);
}
strcpy(tnp, "_p.sp");
- if (read_xspect(&p_sp, tname) == 0) {
+ if (read_xspect(&p_sp, NULL, tname) == 0) {
rd_p = 1;
/* Should read instrument type from debug_p.sp !! */
if (inst_illuminant(&insp, instI1Pro) != 0) /* Hack !! */
@@ -548,8 +548,8 @@ int main(int argc, char *argv[])
printf("Instrument lacks spectral measurement capability");
}
- if (refrmode >= 0 && !IMODETST(cap, inst_mode_emis_refresh_ovd)
- && !IMODETST(cap, inst_mode_emis_norefresh_ovd)) {
+ if (refrmode >= 0 && it->check_mode(it, inst_mode_emis_refresh_ovd) != inst_ok
+ && it->check_mode(it, inst_mode_emis_norefresh_ovd) != inst_ok) {
if (verb) {
printf("Requested refresh mode override and instrument doesn't support it (ignored)\n");
refrmode = -1;
@@ -570,9 +570,9 @@ int main(int argc, char *argv[])
it->capabilities(it, &cap, &cap2, &cap3);
if (c == '1') {
- if (IMODETST(cap, inst_mode_emis_ambient)) {
+ if (it->check_mode(it, inst_mode_emis_ambient) == inst_ok) {
mode = inst_mode_emis_ambient;
- } else if (IMODETST(cap, inst_mode_emis_spot)) {
+ } else if (it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
mode = inst_mode_emis_spot;
} else {
printf("!!! Instrument doesn't have ambient or emissive capability !!!\n");
@@ -580,9 +580,9 @@ int main(int argc, char *argv[])
}
}
if (c == '2') {
- if (IMODETST(cap, inst_mode_emis_tele)) {
+ if (it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
mode = inst_mode_emis_tele;
- } else if (IMODETST(cap, inst_mode_emis_spot)) {
+ } else if (it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
mode = inst_mode_emis_spot;
} else {
printf("!!! Instrument doesn't have telephoto or emissive capability !!!\n");
@@ -592,7 +592,7 @@ int main(int argc, char *argv[])
if (c == '3') {
inst_opt_filter filt;
- if (IMODETST(cap, inst_mode_ref_spot)) {
+ if (it->check_mode(it, inst_mode_ref_spot) == inst_ok) {
mode = inst_mode_ref_spot;
} else {
printf("!!! Instrument lacks reflective spot measurement capability !!!\n");
@@ -769,7 +769,7 @@ int main(int argc, char *argv[])
} else {
if (c == '1') {
- if (IMODETST(cap, inst_mode_emis_ambient)) {
+ if (it->check_mode(it, inst_mode_emis_ambient) == inst_ok) {
printf("\n(If applicable) set instrument to ambient measurenent mode, or place\n");
printf("ambient adapter on it, and position it so as to measure the illuminant directly.\n");
} else {
@@ -777,7 +777,7 @@ int main(int argc, char *argv[])
printf("and position it so as to measure the illuminant directly.\n");
}
} else if (c == '2') {
- if (IMODETST(cap, inst_mode_emis_tele)) {
+ if (it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
printf("\n(If applicable) set instrument to telephoto measurenent mode,\n");
printf("position it so as to measure the illuminant reflected from the paper.\n");
} else {
@@ -921,19 +921,19 @@ int main(int argc, char *argv[])
continue;
}
- if (c == '1') {
+ if (c == '1') { /* Illuminant */
i_sp = val.sp;
if (tmode && rd_i == 0) {
strcpy(tnp, "_i.sp");
- write_xspect(tname,&i_sp);
+ write_xspect(tname, inst_mrt_emission, &i_sp);
}
- } else if (c == '2') {
+ } else if (c == '2') { /* Illuminant reflected on paper */
r_sp = val.sp;
if (tmode && rd_r == 0) {
strcpy(tnp, "_r.sp");
- write_xspect(tname,&r_sp);
+ write_xspect(tname, inst_mrt_emission, &r_sp);
}
- } else if (c == '3') {
+ } else if (c == '3') { /* Paper reflectance */
p_sp = val.sp;
/* Get the illuminant spectrum too */
@@ -943,7 +943,7 @@ int main(int argc, char *argv[])
if (tmode && rd_p == 0) {
/* Should save instrument type/instrument illuminant spectrum !!! */
strcpy(tnp, "_p.sp");
- write_xspect(tname,&p_sp);
+ write_xspect(tname, inst_mrt_reflective, &p_sp);
}
}
@@ -1125,16 +1125,16 @@ int main(int argc, char *argv[])
for (i = 0; i < ill.spec_n; i++)
ill.spec[i] = aill.spec[i]/nacc;
- if(write_xspect(outname, &ill))
+ if(write_xspect(outname, inst_mrt_ambient, &ill))
printf("\nWriting file '%s' failed\n",outname);
else
printf("\nWriting file '%s' succeeded\n",outname);
if (tmode) {
strcpy(tnp, "_mpir.sp"); // Measured paper under illuminant spectrum
- write_xspect(tname,&bf.srop);
+ write_xspect(tname, inst_mrt_reflective, &bf.srop);
strcpy(tnp, "_cpir.sp"); // Computed paper under illuminant spectrum
- write_xspect(tname,&bf.cpsp);
+ write_xspect(tname, inst_mrt_reflective, &bf.cpsp);
}
}
@@ -1188,9 +1188,9 @@ int main(int argc, char *argv[])
for (j = 0; j < bf.ill.spec_n; j++) {
GCC_BUGFIX(j)
xx[j] = XSPECT_XWL(&bf.ill, j);
- y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
- y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
- y3[j] = value_xspect(&cf.dxx, xx[j]); /* Daylight match (green)*/
+ y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
+ y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
+ y3[j] = value_xspect(&cf.dxx, xx[j]); /* Daylight match (green)*/
}
xmax = bf.ill.spec_wl_long;
@@ -1212,10 +1212,10 @@ int main(int argc, char *argv[])
for (j = 0; j < bf.cpsp.spec_n; j++) {
GCC_BUGFIX(j)
xx[j] = XSPECT_XWL(&bf.cpsp, j);
- y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
- y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
- y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
-// y3[j] = value_xspect(&cpdsp, xx[j]); /* Computed daylight reflectance (green) */
+ y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
+ y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
+ y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
+// y3[j] = value_xspect(&cpdsp, xx[j]); /* Computed daylight reflectance (green) */
}
xmax = bf.cpsp.spec_wl_long;
@@ -1233,8 +1233,8 @@ int main(int argc, char *argv[])
for (j = 0; j < bf.ill.spec_n; j++) {
GCC_BUGFIX(j)
xx[j] = XSPECT_XWL(&bf.ill, j);
- y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
- y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
+ y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
+ y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
}
xmax = bf.ill.spec_wl_long;
@@ -1248,9 +1248,9 @@ int main(int argc, char *argv[])
for (j = 0; j < bf.cpsp.spec_n; j++) {
GCC_BUGFIX(j)
xx[j] = XSPECT_XWL(&bf.cpsp, j);
- y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
- y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
- y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
+ y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
+ y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
+ y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
}
xmax = bf.cpsp.spec_wl_long;
diff --git a/spectro/inst.c b/spectro/inst.c
index 8976669..681ef0a 100644
--- a/spectro/inst.c
+++ b/spectro/inst.c
@@ -1,5 +1,5 @@
- /* Abstract instrument class implemenation */
+/* Abstract instrument class implemenation */
/*
* Argyll Color Correction System
@@ -373,6 +373,7 @@ static inst_code calibrate(
inst *p,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN]) { /* Condition identifier (ie. white reference ID, filter ID) */
return inst_unsupported;
}
@@ -585,7 +586,7 @@ static inst_config config_enum(inst *p, int ec) {
/* Delete things set/done by new_inst() */
static inst_code virtual_del(inst *p) {
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
osx_latencycritical_end();
#endif
@@ -612,7 +613,7 @@ void *cntx /* Context for callback */
return NULL;
}
- a1logd(log, 2, "new_inst: called with path '%s'\n",path->name);
+ a1logd(log, 2, "new_inst: called with path '%s' type '%s'\n",path->name,inst_sname(path->itype));
if ((icom = new_icoms(path, log)) == NULL) {
a1logd(log, 2, "new_inst: new_icoms failed to open it\n");
@@ -625,14 +626,19 @@ void *cntx /* Context for callback */
itype = icom->itype; /* Instrument type if its known from usb/hid */
#if defined(ENABLE_FAST_SERIAL)
- if (itype == instUnknown && !nocoms && (icom->sattr & icom_fast)) {
+ if (itype == instUnknown && !nocoms && (icom->dctype & icomt_fastserial)) {
itype = fast_ser_inst_type(icom, 1, uicallback, cntx); /* Else type from serial */
+ icom->dctype = (icom->dctype & ~icomt_cat_mask) | inst_category(itype);
+ a1logd(log, 8, "new_inst: fast set '%s' dctype 0x%x\n",icom->name,icom->dctype);
}
#endif /* ENABLE_FAST_SERIAL */
#if defined(ENABLE_SERIAL)
- if (itype == instUnknown && !nocoms)
+ if (itype == instUnknown && !nocoms) {
itype = ser_inst_type(icom, uicallback, cntx); /* Else type from serial */
+ icom->dctype = (icom->dctype & ~icomt_cat_mask) | inst_category(itype);
+ a1logd(log, 8, "new_inst: set '%s' dctype 0x%x\n",icom->name,icom->dctype);
+ }
#endif /* ENABLE_SERIAL */
@@ -657,7 +663,8 @@ void *cntx /* Context for callback */
#ifdef ENABLE_FAST_SERIAL
if (itype == instSpecbos1201
- || itype == instSpecbos)
+ || itype == instSpecbos
+ || itype == instSpectraval)
p = (inst *)new_specbos(icom, itype);
if (itype == instKleinK10)
p = (inst *)new_kleink10(icom, itype);
@@ -696,8 +703,10 @@ void *cntx /* Context for callback */
p = (inst *)new_huey(icom, itype);
else if (itype == instSmile)
p = (inst *)new_i1disp(icom, itype);
+#ifdef ENABLE_FAST_SERIAL
else if (itype == instSMCube)
p = (inst *)new_smcube(icom, itype);
+#endif
else if (itype == instHCFR)
p = (inst *)new_hcfr(icom, itype);
else if (itype == instColorHug
@@ -799,7 +808,7 @@ void *cntx /* Context for callback */
/* Set the provided user interaction callback */
p->set_uicallback(p, uicallback, cntx);
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
osx_latencycritical_start();
#endif
@@ -917,8 +926,10 @@ int doccmx /* Add matching installed ccmx files */
for (i = 0; ss_list[i].path != NULL; i++) {
- if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL)
+ if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL) {
+ free_iccss(ss_list);
return inst_internal_error;
+ }
list[nlist-1].flags = inst_dtflags_ccss | inst_dtflags_ld | inst_dtflags_wr;
if (!ss_list[i].oem)
@@ -938,6 +949,7 @@ int doccmx /* Add matching installed ccmx files */
list[nlist-1].sets = ss_list[i].sets; ss_list[i].sets = NULL;
list[nlist-1].no_sets = ss_list[i].no_sets; ss_list[i].no_sets = 0;
}
+ free_iccss(ss_list);
}
/* Add any OEM and custom ccmx's */
@@ -963,8 +975,10 @@ int doccmx /* Add matching installed ccmx files */
continue;
}
- if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL)
+ if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL) {
+ free_iccmx(ss_list);
return inst_internal_error;
+ }
list[nlist-1].flags = inst_dtflags_ccmx | inst_dtflags_ld | inst_dtflags_wr;
if (!ss_list[i].oem)
@@ -984,6 +998,7 @@ int doccmx /* Add matching installed ccmx files */
list[nlist-1].cc_cbid = ss_list[i].cc_cbid;
icmCpy3x3(list[nlist-1].mat, ss_list[i].mat);
}
+ free_iccmx(ss_list);
}
/* Copy candidate selectors to private isel[] list */
@@ -1047,6 +1062,39 @@ int doccmx /* Add matching installed ccmx files */
return inst_ok;
}
+/* --------------------------------------------------- */
+
+/* Delayed scan-ready prompt handler */
+static int delayed_scan_ready(void *pp) {
+ inst *p = (inst *)pp;
+
+ msec_sleep(p->scan_ready_delay);
+ a1logd(g_log,8, "delayed scan_ready activate\n");
+
+ if (p->eventcallback != NULL)
+ p->eventcallback(p->event_cntx, inst_event_scan_ready);
+ return 0;
+}
+
+/* Issue an inst_event_scan_ready event/prompt after a delay */
+void issue_scan_ready(inst *p, int delay) {
+ a1logd(g_log,8, "msec_scan_ready %d msec\n",delay);
+
+ if (p->eventcallback == NULL) /* Hmm. */
+ return;
+
+ if (delay > 0) {
+ if (p->scan_ready_thread != NULL)
+ p->scan_ready_thread->del(p->scan_ready_thread);
+ p->scan_ready_delay = delay;
+ if ((p->scan_ready_thread = new_athread(delayed_scan_ready, (void *)p)) == NULL)
+ a1logw(g_log, "msec_scan_ready: Delayed scan_ready failed to create thread\n");
+ } else {
+ a1logd(g_log,8, "msec_scan_ready activate\n");
+ p->eventcallback(p->event_cntx, inst_event_scan_ready);
+ }
+}
+
/* ============================================================= */
/* CCMX location support */
@@ -1089,6 +1137,7 @@ iccmx *list_iccmx(instType itype, int *no) {
free(rv[j].desc);
}
xdg_free(paths, npaths);
+ free(rv);
if (no != NULL) *no = -1;
return NULL;
}
@@ -1098,8 +1147,10 @@ iccmx *list_iccmx(instType itype, int *no) {
}
/* Skip any that don't match */
- if (itype != instUnknown && cs->inst != NULL && inst_enum(cs->inst) != itype)
+ if (itype != instUnknown && cs->inst != NULL && inst_enum(cs->inst) != itype) {
+ cs->del(cs);
continue;
+ }
a1logd(g_log, 5, "Reading '%s'\n",paths[i]);
if ((tech = cs->tech) == NULL)
@@ -1336,21 +1387,38 @@ instType fast_ser_inst_type(
void *cntx /* Context for callback */
) {
instType rv = instUnknown;
-#define BUFSZ (128 + 10)
+#define BUFSZ (2048 + 10)
char buf[BUFSZ];
- baud_rate brt[] = { baud_921600, baud_115200, baud_38400, baud_9600, baud_nc };
+ baud_rate brt1[] = { baud_9600, baud_921600, baud_115200,
+ baud_38400, baud_nc }; /* HS - do K10/Spectrolino first */
+ baud_rate brt2[] = { baud_115200, baud_nc }; /* Bluetooth */
+
+ baud_rate *brt = brt1;
unsigned int etime;
unsigned int i;
+ int delayms = 0;
int se, len;
+ double tryto = 0.1; /* [0.1] Communication timout */
+// double tryto = 0.9; /* Communication timout (test) */
- if (p->port_type(p) != icomt_serial
- && p->port_type(p) != icomt_usbserial)
+ a1logd(p->log, 8, "fast_ser_inst_type: on '%s' dctype 0x%x\n",p->name,p->dctype);
+
+ if (!(p->dctype & icomt_seriallike)
+ && !(p->dctype & icomt_fastserial)) {
return p->itype;
+ }
/* The tick to give up on */
etime = msec_time() + (long)(2000.0 + 0.5);
+// etime = msec_time() + (long)(20000.0 + 0.5); /* (test) */
- a1logd(p->log, 1, "fser_inst_type: Trying different baud rates (%u msec to go)\n",etime - msec_time());
+ a1logd(p->log, 1, "fser_inst_type: Trying different baud rates (%u msec to go) Path %s%s\n",
+ etime - msec_time(),p->spath,(p->dctype & icomt_btserial) ? " [Bluetooth]" : "");
+
+ if (p->dctype & icomt_btserial) {
+ brt = brt2; /* Only try BT relevant baud rates. */
+ delayms = 600; /* Spectraval locks up otherwise. */
+ }
/* Until we time out, find the correct baud rate */
for (i = 0; msec_time() < etime; i++) {
@@ -1361,40 +1429,97 @@ instType fast_ser_inst_type(
}
a1logd(p->log, 5, "Trying %s baud\n",baud_rate_to_str(brt[i]));
- if ((se = p->set_ser_port(p, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
+ if ((se = p->set_ser_port_ex(p, fc_None, brt[i], parity_none,
+ stop_1, length_8, delayms)) != ICOM_OK) {
a1logd(p->log, 5, "fser_inst_type: set_ser_port failed with 0x%x\n",se);
- return instUnknown; /* Give up */
+ return instUnknown; /* Give up on port */
}
- if (brt[i] == baud_9600) {
- /* See if it's a Klein K10 */
+ /* Assume Klein K10 only uses 9600. */
+ /* We need to also assume that we might be talking to a Spectrolino, */
+ /* and avoid upsetting it. */
+ if ((p->dctype & icomt_btserial) == 0 && brt[i] == baud_9600) {
+ double sto = 0.2; /* Give 9600 a little more time */
+ int bread, len;
+
+ /* Try a spectrolino/spectroscan command first */
+ if (tryto > sto)
+ sto = tryto;
+ p->write_read_ex(p, ";D024\r\n", 0, buf, BUFSZ-1, &bread, "\r", 1, sto, 1);
+
+ if (bread == 0) {
+ a1logd(p->log, 5, "fser_inst_type: Spectroino command returned nothing\n");
+ goto not_k10;
+ }
+ buf[bread] = '\000';
+ len = strlen(buf);
+
+ a1logd(p->log, 5, "fser_inst_type: got %d bytes\n",len);
- if ((se = p->write_read(p, "P0\r", 0, buf, BUFSZ, NULL, ">", 1, 0.100)) != inst_ok) {
- /* Check for user abort */
- if (uicallback != NULL) {
- inst_code ev;
- if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
+ if (len < 4) {
+ a1logd(p->log, 5, "fser_inst_type: Reply was too short\n");
+ goto not_k10; /* Not K10, X-Rite or Spectrolino */
+ }
+
+ /* Is this a Spectrolino or Spectroscan error resonse ? */
+ if (len >= 5 && strncmp(buf, ":26", 3) == 0
+ || len >= 7 && strncmp(buf, ":D183", 5) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: Ignore Spectrolino\n");
+ return instUnknown; /* Not doing Spectrolino detection here */
+ }
+
+ /* Is this an X-Rite error value such as "<01>" ? */
+ if (buf[0] == '<' && isdigit(buf[1]) && isdigit(buf[2]) && buf[3] == '>') {
+ a1logd(p->log, 5, "fser_inst_type: Ignore X-Rite\n");
+ return instUnknown; /* Not doing X-Rite detection here */
+ }
+
+ /* The Klein K10 seems to respond with it's calibration list, preceeded by "D4" ? */
+ if (buf[0] != 'D' || buf[1] != '4') {
+ a1logd(p->log, 5, "fser_inst_type: Not Klein response\n");
+ goto not_k10;;
+ }
+
+ a1logd(p->log, 5, "fser_inst_type: Looks like it may be a Klein\n");
+
+ /* Confirm this is a Klein instrument */
+
+ /* The first response is the calibration list, and it may need flushing. */
+ /* (write_read_ex doesn't cope with time it takes to dump this.) */
+ for (;;) {
+ bread = 0;
+ p->read(p, buf, BUFSZ, &bread, NULL, BUFSZ, 0.1);
+ if (bread == 0)
+ break;
+ }
+
+ if ((se = p->write_read_ex(p, "P0\r", 0, buf, BUFSZ, NULL, ">", 1, tryto, 1)) == inst_ok) {
+
+ /* Is this a Klein K1/K8/K10 response ? */
+ if (strncmp(buf, "P0K-1 ", 6) == 0
+ || strncmp(buf, "P0K-8 ", 6) == 0
+ || strncmp(buf, "P0K-10", 6) == 0
+ || strncmp(buf, "P0KV-10", 7) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: found Klein K1/K8/K10\n");
+ rv = instKleinK10;
+ break;
+ }
+ }
+
+ not_k10:;
+
+ /* Check for user abort */
+ if (uicallback != NULL) {
+ inst_code ev;
+ if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
a1logd(p->log, 5, "fser_inst_type: User aborted\n");
return instUnknown;
- }
}
- continue;
- }
- len = strlen(buf);
-
- /* Is this a Klein K1/K8/K10 response ? */
- if (strncmp(buf, "P0K-1 ", 6) == 0
- || strncmp(buf, "P0K-8 ", 6) == 0
- || strncmp(buf, "P0K-10", 6) == 0
- || strncmp(buf, "P0KV-10", 7) == 0) {
- a1logd(p->log, 5, "fser_inst_type: found Klein K1/K8/K10\n");
- rv = instKleinK10;
- break;
}
}
- if (brt[i] == baud_38400)
- {
+
+ /* SwatchMate Cube only uses 38400 */
+ if ((p->dctype & icomt_btserial) == 0 && brt[i] == baud_38400) {
int bread;
/* See if it's a SwatchMate Cube. */
@@ -1403,56 +1528,81 @@ instType fast_ser_inst_type(
buf[1] = 0x00;
buf[2] = 0x02; /* Ping command */
buf[3] = 0x00;
- if ((se = p->write_read(p, buf, 4, buf, BUFSZ, &bread, NULL, 4, 0.100)) != inst_ok) {
- /* Check for user abort */
- if (uicallback != NULL) {
- inst_code ev;
- if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
- a1logd(p->log, 5, "fser_inst_type: User aborted\n");
- return instUnknown;
+ if ((se = p->write_read_ex(p, buf, 4, buf, BUFSZ, &bread, NULL, 4, tryto, 1)) == inst_ok) {
+ if (bread == 4) {
+ if (buf[0] == 0x7e && buf[1] == 0x20 && buf[2] == 0x02 && buf[3] == 0x00) {
+ a1logd(p->log, 5, "fser_inst_type: found SwatchMate Cube\n");
+ rv = instSMCube;
+ break;
}
}
- continue;
}
- if (bread == 4) {
- if (buf[0] == 0x7e && buf[1] == 0x20 && buf[2] == 0x02 && buf[3] == 0x00) {
- a1logd(p->log, 5, "fser_inst_type: found SwatchMate Cube\n");
- rv = instSMCube;
- break;
+
+ /* Check for user abort */
+ if (uicallback != NULL) {
+ inst_code ev;
+ if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 5, "fser_inst_type: User aborted\n");
+ return instUnknown;
}
}
}
- /* Bluetooth only uses baud_115200 */
- if ((p->sattr & icom_bt) == 0 || brt[i] == baud_115200) {
+
+ /* JETI specbos or spectraval. */
+ /* We are fudging the baud rate selection here - */
+ /* the 1211 RS and BT can't handle 921600, */
+ /* while the 15x1 can handle 230400 & 3000000, which we don't test for... */
+// if ((p->dctype & icomt_btserial) == 0 || brt[i] == baud_115200)
+ if (brt[i] == baud_38400 || brt[i] == baud_115200 || brt[i] == baud_921600)
+ {
+ int bread;
/* See if it's a JETI specbos */
- if ((se = p->write_read(p, "*idn?\r", 0, buf, BUFSZ, NULL, "\r", 1, 0.100)) != inst_ok) {
- /* Check for user abort */
- if (uicallback != NULL) {
- inst_code ev;
- if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
- a1logd(p->log, 5, "fser_inst_type: User aborted\n");
- return instUnknown;
- }
+ p->write_read_ex(p, "*idn?\r", 0, buf, BUFSZ, &bread, "\r", 1, tryto, 1);
+ if (bread > 0) {
+ len = strlen(buf);
+
+ /* JETI specbos returns "JETI_SBXXXX", where XXXX is the instrument type, */
+ /* except for the 1201 which returns "SB05" */
+ /* The spectraval 1501 returns JETI_SDCM3 NNNNNNN */
+
+ /* Over Bluetooth, we get an erronious string "AT+JSCR\r\n" mixed in our output. */
+ /* This would appear to be from the eBMU Bluetooth adapter AT command set. */
+ if (len > 9 && strncmp(buf, "AT+JSCR\r\n", 9) == 0) {
+ memmove(buf, buf+9, len-9);
+ len -= 9;
+ }
+
+ /* Is this a JETI specbos 1201 response ? */
+ if (strncmp(buf, "SB05", 4) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: found JETI specbos 1201\n");
+ rv = instSpecbos1201;
+ break;
+ }
+ /* Is this a JETI specbos XXXX response ? */
+ if (len >= 11 && strncmp(buf, "JETI_SB", 7) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: found JETI specbos\n");
+ rv = instSpecbos;
+ break;
+ }
+ /* Is this a JETI spectraval response ? */
+ /* (Bluetooth returns "DCM3_JETI ... and other rubbish for some reason.) */
+ if ((len >= 10 && strncmp(buf, "JETI_SDCM3", 10) == 0)
+ || (len >= 9 && strncmp(buf, "DCM3_JETI", 9) == 0)
+ || (len >= 17 && strncmp(buf, "PECFIRM_JETI_1501", 17) == 0)
+ || (len >= 18 && strncmp(buf, "SPECFIRM_JETI_1501", 18) == 0)) {
+ a1logd(p->log, 5, "fser_inst_type: found JETI spectraval\n");
+ rv = instSpectraval;
+ break;
}
- continue;
- }
- len = strlen(buf);
-
- /* JETI specbos returns "JETI_SBXXXX", where XXXX is the instrument type, */
- /* except for the 1201 which returns "SB05" */
-
- /* Is this a JETI specbos 1201 response ? */
- if (strncmp(buf, "SB05", 4) == 0) {
- a1logd(p->log, 5, "fser_inst_type: found JETI specbos 1201\n");
- rv = instSpecbos1201;
- break;
}
- /* Is this a JETI specbos XXXX response ? */
- if (len >= 11 && strncmp(buf, "JETI_SB", 7) == 0) {
- a1logd(p->log, 5, "fser_inst_type: found JETI specbos\n");
- rv = instSpecbos;
- break;
+ /* Check for user abort */
+ if (uicallback != NULL) {
+ inst_code ev;
+ if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 5, "fser_inst_type: User aborted\n");
+ return instUnknown;
+ }
}
}
}
@@ -1492,11 +1642,12 @@ static instType ser_inst_type(
#define BUFSZ (128 + 10)
char buf[BUFSZ];
baud_rate brt[] = { baud_9600, baud_19200, baud_4800, baud_2400,
- baud_1200, baud_38400, baud_57600, baud_115200,
- baud_600, baud_300, baud_110, baud_nc };
+ baud_1200, baud_38400, baud_57600, baud_115200,
+ baud_600, baud_300, baud_110, baud_nc };
unsigned int etime;
unsigned int bi, i;
int se, len, bread;
+ int klein = 0;
int xrite = 0;
int ss = 0;
int so = 0;
@@ -1517,7 +1668,7 @@ static instType ser_inst_type(
for (i = bi; msec_time() < etime; i++) {
if (brt[i] == baud_nc)
i = 0;
- if ((se = p->set_ser_port(p, fc_none, brt[i], parity_none,
+ if ((se = p->set_ser_port(p, fc_None, brt[i], parity_none,
stop_1, length_8)) != ICOM_OK) {
a1logd(p->log, 5, "ser_inst_type: set_ser_port failed with 0x%x\n",se);
return instUnknown; /* Give up */
@@ -1525,7 +1676,11 @@ static instType ser_inst_type(
a1logd(p->log, 5, "Trying %s baud\n",baud_rate_to_str(brt[i]));
bread = 0;
- if ((se = p->write_read(p, ";D024\r\n", 0, buf, BUFSZ, &bread, "\r", 1, 0.5)) != inst_ok) {
+
+ /* Try a spectrolino/spectroscan command first */
+ p->write_read_ex(p, ";D024\r\n", 0, buf, BUFSZ-1, &bread, "\r", 1, 0.5, 1);
+
+ if (bread == 0) {
/* Check for user abort */
if (uicallback != NULL) {
inst_code ev;
@@ -1534,15 +1689,24 @@ static instType ser_inst_type(
return instUnknown;
}
}
- if (bread == 0)
- continue;
+ continue;
}
+ buf[bread] = '\000';
len = strlen(buf);
// a1logd(p->log, 5, "len = %d\n",len);
if (len < 4)
continue;
+ /* The Klein K10 seems to respond with it's calibration list, preceeded by "D4" ? */
+ /* - don't know how reliable this is though. Another way may be to look for a */
+ /* response len > 100 characters ?? */
+ if (buf[0] == 'D' && buf[1] == '4') {
+// a1logd(p->log, 5, "klein\n");
+ klein = 1;
+ break;
+ }
+
/* Is this an X-Rite error value such as "<01>" ? */
if (buf[0] == '<' && isdigit(buf[1]) && isdigit(buf[2]) && buf[3] == '>') {
// a1logd(p->log, 5, "xrite\n");
@@ -1580,7 +1744,7 @@ static instType ser_inst_type(
/* SpectroScan */
if (ss) {
rv = instSpectroScan;
- if ((se = p->write_read(p, ";D030\r\n", 0, buf, BUFSZ, NULL, "\n", 1, 1.5)) == 0) {
+ if ((se = p->write_read_ex(p, ";D030\r\n", 0, buf, BUFSZ, NULL, "\n", 1, 1.5, 1)) == 0) {
if (strlen(buf) >= 41) {
hex2bin(&buf[5], 12);
// a1logd(p->log, 5, "spectroscan type = '%s'\n",buf);
@@ -1592,7 +1756,7 @@ static instType ser_inst_type(
if (xrite) {
/* Get the X-Rite model and version number */
- if ((se = p->write_read(p, "SV\r\n", 0, buf, BUFSZ, NULL, ">", 1, 2.5)) != 0)
+ if ((se = p->write_read_ex(p, "SV\r\n", 0, buf, BUFSZ, NULL, ">", 1, 2.5, 1)) != 0)
return instUnknown;
if (strlen(buf) >= 12) {
@@ -1613,6 +1777,31 @@ static instType ser_inst_type(
}
}
+ if (klein) {
+
+ /* The first response is the calibration list, and it may need flushing. */
+ /* (write_read_ex doesn't cope with time it takes to dump this.) */
+ for (;;) {
+ bread = 0;
+ p->read(p, buf, BUFSZ, &bread, NULL, BUFSZ, 0.1);
+ if (bread == 0)
+ break;
+ }
+
+ /* See if this is a Klein K10 or similar */
+ if ((se = p->write_read_ex(p, "P0\r", 0, buf, BUFSZ, NULL, ">", 1, 1.5, 1)) != inst_ok)
+ return instUnknown;
+
+ /* Is this a Klein K1/K8/K10 response ? */
+ if (strncmp(buf, "P0K-1 ", 6) == 0
+ || strncmp(buf, "P0K-8 ", 6) == 0
+ || strncmp(buf, "P0K-10", 6) == 0
+ || strncmp(buf, "P0KV-10", 7) == 0) {
+ a1logd(p->log, 5, "fser_inst_type: found Klein K1/K8/K10\n");
+ rv = instKleinK10;
+ }
+ }
+
a1logd(p->log, 5, "ser_inst_type: Instrument type is '%s'\n", inst_name(rv));
p->close_port(p); /* Or should we leave it open ?? */
@@ -1732,6 +1921,25 @@ int sym_to_inst_mode(inst_mode *mode, const char *sym) {
return rv;
}
+/* ============================================================= */
+/* Utilities */
+
+/* Return a string for the xcalstd enum */
+char *xcalstd2str(xcalstd std) {
+ switch(std) {
+ case xcalstd_native:
+ return "NATIVE";
+ case xcalstd_xrdi:
+ return "XRDI";
+ case xcalstd_gmdi:
+ return "GMDI";
+ case xcalstd_xrga:
+ return "XRGA";
+ default:
+ break;
+ }
+ return "None";
+}
diff --git a/spectro/inst.h b/spectro/inst.h
index 736a879..01f579d 100644
--- a/spectro/inst.h
+++ b/spectro/inst.h
@@ -1,13 +1,15 @@
#ifndef INST_H
- /* instlib API definition. */
-
- /* See spotread.c, chartread.c, illumread.c & ccxxmake.c for examples of */
- /* the API usage. */
-
- /* Abstract base class for common color instrument interface */
- /* and other common instrument stuff. */
+/*
+ * instlib API definition.
+ *
+ * See spotread.c, chartread.c, illumread.c & ccxxmake.c for examples of
+ * the API usage.
+ *
+ * Abstract base class for common color instrument interface
+ * and other common instrument stuff.
+ */
/*
* Argyll Color Correction System
@@ -64,7 +66,7 @@
/* ------------------------------------------------- */
/* Structure for holding an instrument patch reading */
-#define ICOM_MAX_LOC_LEN 10
+#ifdef NEVER /* Declared in xicc/xspect.h */
/* Type of measurement result */
typedef enum { /* XYZ units, Spectral units */
@@ -78,6 +80,10 @@ typedef enum { /* XYZ units, Spectral units */
inst_mrt_frequency = 7 /* Hz */
} inst_meas_type;
+#endif // NEVER
+
+#define ICOM_MAX_LOC_LEN 10
+
struct _ipatch {
char loc[ICOM_MAX_LOC_LEN]; /* patch location */
@@ -95,11 +101,25 @@ struct _ipatch {
}; typedef struct _ipatch ipatch;
+/* ------------------------------------------------------ */
+/* Gretag/X-Rite specific reflective measurement standard */
+
+typedef enum {
+ xcalstd_none = -2, /* Not set */
+ xcalstd_native = -1, /* No conversion */
+ xcalstd_xrdi = 0, /* Historical X-Rite */
+ xcalstd_gmdi = 1, /* Historical Gretag-Macbeth */
+ xcalstd_xrga = 2, /* Current X-Rite */
+} xcalstd;
+
+/* Return a string for the xcalstd enum */
+char *xcalstd2str(xcalstd std);
+
/* ---------------------------------------- */
/* Instrument interface abstract base class */
-/* Abstract return codes in ms byte. */
-/* Instrument dependant codes in ls byte. */
+/* Abstract return codes in ms 8bits. */
+/* Instrument dependant codes in ls 16 bits. */
/* Note :- update inst_interp_error() in inst.c if anything here is changed. */
/* and also check all the instrument specific XXX_interp_code() routines too. */
typedef enum {
@@ -163,7 +183,7 @@ typedef enum {
typedef enum {
inst_mode_none = 0x00000000, /* No capability or mode */
- /* Mode of light measurement */
+ /* Light measurement mode */
inst_mode_reflection = 0x00000001, /* General reflection mode */
# define inst_mode_reflection_sym "REFL"
inst_mode_s_reflection = 0x00000002, /* General saved reflection mode */
@@ -174,7 +194,7 @@ typedef enum {
# define inst_mode_emission_sym "EMIS"
inst_mode_illum_mask = 0x0000000f, /* Mask of sample illumination sub mode */
- /* Access mode of measurement */
+ /* Action of measurement */
inst_mode_spot = 0x00000010, /* General spot measurement mode */
# define inst_mode_spot_sym "SPOT"
inst_mode_strip = 0x00000020, /* General strip measurement mode */
@@ -241,7 +261,9 @@ typedef enum {
| inst_mode_s_reflection,
inst_mode_trans_spot = inst_mode_spot /* Transmission spot measurement mode */
- | inst_mode_transmission,
+ | inst_mode_transmission, /* Normal Diffuse/90 */
+ inst_mode_trans_spot_a = inst_mode_ambient /* Transmission spot measurement mode */
+ | inst_mode_transmission, /* Alternate 90/diffuse */
inst_mode_trans_strip = inst_mode_strip /* Transmission strip measurement mode */
| inst_mode_transmission,
inst_mode_trans_xy = inst_mode_xy /* Transmission X-Y measurement mode */
@@ -267,6 +289,8 @@ typedef enum {
} inst_mode;
/* Test for a specific mode */
+/* (This isn't foolproof - it->check_mode() is better for modes */
+/* composed of more than one bit) */
#define IMODETST(mbits, mode) (((mbits) & (mode)) == (mode))
/* Test for a specific mode in capability and mode */
@@ -299,8 +323,11 @@ typedef enum {
inst2_emis_refr_meas = 0x00000080, /* Has an emissive refresh rate measurement func. */
inst2_prog_trig = 0x00000100, /* Progromatic trigger measure capability */
- inst2_user_trig = 0x00000200, /* User trigger measure capability */
- inst2_switch_trig = 0x00000400, /* Inst. switch trigger measure capability */
+ inst2_user_trig = 0x00000200, /* User trigger measure capability, */
+ /* i.e. via user button and uicallback. */
+ inst2_switch_trig = 0x00000400, /* Inst. switch trigger measure capability, */
+ /* i.e. instrument directly starts measurement */
+ /* via mechanical switch. */
inst2_user_switch_trig = 0x00000800, /* User or switch trigger measure capability */
inst2_bidi_scan = 0x00001000, /* Try and recognise patches scanned from either dir. */
@@ -356,6 +383,11 @@ typedef enum {
optional password
configuration specific calibrations. How are they marked ?
+
+
+ Also for ccss capable instruments:
+
+ write corresponding ccmx for given ccss.
*/
typedef enum {
@@ -446,7 +478,7 @@ typedef enum {
inst_opt_trig_prog = 0x000E, /* Trigger progromatically [No args] */
inst_opt_trig_user = 0x000F, /* Trigger from user via uicallback [No args] */
- inst_opt_trig_switch = 0x0010, /* Trigger using instrument switch [No args] */
+ inst_opt_trig_switch = 0x0010, /* Trigger directly using instrument switch [No args] */
inst_opt_trig_user_switch = 0x0011, /* Trigger from user via uicallback or switch (def) [No args] */
inst_opt_highres = 0x0012, /* Enable high res spectral mode indep. of set_mode() */
@@ -468,12 +500,24 @@ typedef enum {
inst_opt_get_min_int_time = 0x001D, /* Get the minimum integration time [*double time] */
inst_opt_set_min_int_time = 0x001E, /* Set the minimum integration time [double time] */
- inst_opt_opt_calibs_valid = 0x001F, /* Are optional calibrations valid [*int valid] */
- inst_opt_clear_opt_calibs = 0x0020 /* Clear all optional calibrations. */
+ inst_opt_opt_calibs_valid = 0x001F, /* Are optional (white/black/gloss etc.) calibrations */
+ /* valid? [*int valid] */
+ inst_opt_clear_opt_calibs = 0x0020, /* Clear all optional calibrations. */
+
+ inst_opt_get_cal_tile_sp = 0x0021, /* Return refl. white tile reference spectrum. */
+ /* for current filter. [*xspect tile] */
+
+ inst_opt_set_xcalstd = 0x0022, /* Set the X-Rite reflective calibration standard */
+ /* [xcalstd standard] */
+ inst_opt_get_xcalstd = 0x0023, /* Get the effective X-Rite ref. cal. standard */
+ /* [xcalstd *standard] */
+ inst_opt_lamp_remediate = 0x0024 /* Remediate i1Pro lamp [double seconds] */
+
} inst_opt_type;
/* Optional filter fitted to instrument (for inst_opt_set_filter) */
+/* Set this before calling init_coms() */
typedef enum {
inst_opt_filter_unknown = 0xffff, /* Unspecified filter */
inst_opt_filter_none = 0x0000, /* No filters fitted */
@@ -588,24 +632,42 @@ typedef enum {
} inst_cal_cond;
+/* Condition identifier message type. This can be useful in internationalizing the */
+/* string returned in id[] from calibrate() */
+typedef enum {
+ inst_calc_id_none = 0x00000000, /* No id */
+ inst_calc_id_ref_sn = 0x00000001, /* Calibration reference (ie. tile) serial number */
+
+ inst_calc_id_trans_low = 0x00010000, /* Trans. Ref. light is too low for accuracy warning */
+ inst_calc_id_trans_wl = 0x00020000, /* Trans. Ref. light is low at some wavelengths warning */
+ inst_calc_id_filt_unkn = 0x00100000, /* Request unknown filter */
+ inst_calc_id_filt_none = 0x00200000, /* Request no filter */
+ inst_calc_id_filt_pol = 0x00300000, /* Request polarizing filter */
+ inst_calc_id_filt_D65 = 0x00400000, /* Request D65 filter */
+ inst_calc_id_filt_UV = 0x00500000, /* Request UV cut filter */
+ inst_calc_id_filt_cust = 0x00600000 /* Request custom filter */
+} inst_calc_id_type;
+
/* Clamping state */
typedef enum {
instNoClamp = 0, /* Don't clamp XYZ/Lab to +ve */
instClamp = 1, /* Clamp XYZ/Lab to +ve */
} instClamping;
-/* User interaction callback function purpose */
+/* User interaction callback (uicallback()) function purpose */
typedef enum {
- inst_negcoms, /* Negotiating communications */
- inst_triggered, /* Measurement has been triggered by switch or user (not progromatic) */
- inst_armed, /* Armed and waiting for a measurement trigger */
- inst_measuring /* Busy measuring */
+ inst_negcoms, /* Negotiating communications - can abort */
+ inst_armed, /* Armed and waiting for a measurement trigger - can wait, trigger, abort */
+ inst_triggered, /* Measurement triggered by switch or user (not progromatic) - notice */
+ /* (Also triggered by switch driven calibration,i.e. DTP41) */
+ inst_measuring /* Busy measuring - can abort */
} inst_ui_purp;
/* Asynchronous event callback type */
typedef enum {
- inst_event_switch, /* Instrument measure/calibrate switch pressed */
- inst_event_mconf /* Change in measurement configuration (ie. sensor position) */
+ inst_event_switch, /* Instrument measure/calibrate switch pressed. */
+ inst_event_mconf, /* Change in measurement configuration (ie. sensor position) */
+ inst_event_scan_ready /* Ready for manual strip scan (i.e. issue audible prompt) */
} inst_event_type;
/* Instrument configuration/sensor position*/
@@ -641,7 +703,9 @@ typedef enum {
inst_code (*uicallback)(void *cntx, inst_ui_purp purp); \
void *uic_cntx; /* User interaction callback function */ \
void (*eventcallback)(void *cntx, inst_event_type event); \
- void *event_cntx; /* Event callback function */ \
+ void *event_cntx; /* Asynchronous event callback function */ \
+ athread *scan_ready_thread; /* msec_scan_ready() support */ \
+ int scan_ready_delay; /* msec_scan_ready() support */ \
\
/* Virtual delete. Cleans up things done by new_inst(). */ \
inst_code (*vdel)( \
@@ -819,15 +883,15 @@ typedef enum {
\
\
/* Read a set of strips (applicable to strip reader) */ \
- /* Obeys the trigger mode set, and may return user trigger code */ \
- /* (to hint that a user command may be available) */ \
+ /* Obeys the trigger mode set, and may return user trigger code, */ \
+ /* to hint that a user command may be available. */ \
/* Return the inst error code */ \
inst_code (*read_strip)( \
struct _inst *p, \
- char *name, /* Strip name (up to 7 chars) */ \
+ char *name, /* Strip name (up to 7 chars, for DTP51) */ \
int npatch, /* Number of patches in each pass */ \
- char *pname, /* Pass name (3 chars) */ \
- int sguide, /* Guide number (decrements by 5) */ \
+ char *pname, /* Pass name (3 chars, for DTP51) */ \
+ int sguide, /* Guide number (for DTP51, decrements by 5) */ \
double pwid, /* Patch width in mm (For DTP20/DTP41) */ \
double gwid, /* Gap width in mm (For DTP20/DTP41) */ \
double twid, /* Trailer width in mm (For DTP41T) */ \
@@ -836,9 +900,9 @@ typedef enum {
\
/* Read a single sample (applicable to spot instruments) */ \
/* Obeys the trigger mode set, and may return user trigger code */ \
- /* Values are in XYZ 0..100 for reflective transmissive, */ \
- /* aXYZ in cd/m^2 for emissive, amd Lux/3.1415926 for ambient. */ \
- /* Spectral will be analogous to the XYZ. */ \
+ /* Values are in XYZ % (0..100) for reflective & transmissive, */ \
+ /* cd/m^2 for emissive, and Lux for ambient. */ \
+ /* Spectral will be analogous to the XYZ (see inst_meas_type). */ \
/* By default values may be -ve due to noise (depending on instrument) */ \
/* Return the inst error code */ \
inst_code (*read_sample)( \
@@ -916,8 +980,10 @@ typedef enum {
struct _inst *p, \
inst_cal_type *calt, /* Calibration type to do/remaining */ \
inst_cal_cond *calc, /* Current condition/desired condition */ \
+ inst_calc_id_type *idtype, /* Condition identifier type */ \
char id[CALIDLEN]); /* Condition identifier (ie. white */ \
- /* reference ID, filter ID) */ \
+ /* reference ID, filter ID, message string, */ \
+ /* etc.) */ \
\
/* Measure a display update, and instrument reaction time. It is */ \
/* assumed that a white to black change will be made to the */ \
@@ -1006,12 +1072,12 @@ typedef enum {
* For inst_negcoms, the return value of inst_user_abort \
* will abort the communication negotiation. \
* \
- * For inst_triggered, the return value of the callback is ignored. \
- * \
* For inst_armed return value should be one of: \
* inst_ok to do nothing, inst_user_abort to abort the measurement, \
* or inst_user_trig to trigger the measurement. \
* \
+ * For inst_triggered, the return value of the callback is ignored. \
+ * \
* For inst_measuring the return value should be one of: \
* inst_ok to do nothing, inst_user_abort to abort the measurement. \
* \
@@ -1022,10 +1088,11 @@ typedef enum {
void *cntx); \
\
/* Supply an aynchronous event callback function. \
- * This is called from a thread with the following possible events: \
+ * This is called from a different thread with the following possible events: \
* \
* inst_event_switch: Instrument measure/calibrate switch pressed \
* inst_event_mconf: The measurement configuration has changed (ie. sensor position) \
+ * inst_event_scan_ready: Ready for manual strip scan (i.e. issue audible prompt) \
* \
* NULL can be set to disable the callback. \
*/ \
@@ -1068,7 +1135,8 @@ extern inst *new_inst(
);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/* Implementation functions used by drivers */
+/* Implementation functions used by instrument drivers */
+/* (Client code should not call these) */
/* Get a status or set or get an option (default implementation) */
inst_code inst_get_set_opt_def(
@@ -1090,6 +1158,10 @@ int doccmx /* Add matching installed ccmx files */
/* Free a display type list */
void inst_del_disptype_list(inst_disptypesel *list, int no);
+/* - - - - - - - - - - - - - - - - - - -- */
+
+/* Issue an inst_event_scan_ready event after a delay */
+void issue_scan_ready(inst *p, int delay);
/* - - - - - - - - - - - - - - - - - - -- */
/* CCMX support - ccmx instrument proxy */
diff --git a/spectro/instappsup.c b/spectro/instappsup.c
index d2ce7ff..fc550b4 100644
--- a/spectro/instappsup.c
+++ b/spectro/instappsup.c
@@ -1,5 +1,5 @@
- /* Instrument command line application support functions */
+/* Instrument command line application support functions */
/*
* Argyll Color Correction System
@@ -72,7 +72,6 @@ static inst_code def_uicallback(void *cntx, inst_ui_purp purp) {
return inst_user_trig;
}
- /* Change in measurement configuration */
} else if (purp == inst_measuring) {
return inst_ok;
}
@@ -173,8 +172,9 @@ inst_code inst_handle_calibrate(
int doimmediately /* If nz, don't wait for user, calibrate immediatley */
) {
inst_code rv = inst_ok, ev;
- int usermes = 0; /* User was given a message */
- char id[200]; /* Condition identifier */
+ int usermes = 0; /* User was given a message */
+ inst_calc_id_type idtype; /* Condition identifier type */
+ char id[200]; /* Condition identifier */
int ch;
a1logd(p->log,1,"inst_handle_calibrate called\n");
@@ -183,13 +183,15 @@ inst_code inst_handle_calibrate(
for (;;) {
a1logd(p->log,1,"About to call calibrate at top of loop\n");
- ev = p->calibrate(p, &calt, &calc, id);
+ ev = p->calibrate(p, &calt, &calc, &idtype, id);
a1logd(p->log,1,"Calibrate returned calt 0x%x, calc 0x%x, ev 0x%x\n",calt,calc,ev);
/* We're done */
if ((ev & inst_mask) == inst_ok) {
- if ((calc & inst_calc_cond_mask) == inst_calc_message)
+ if ((calc & inst_calc_cond_mask) == inst_calc_message) {
+ /* (Or could create our own message text based on value of idtype) */
printf("%s\n",id);
+ }
if (usermes)
printf("Calibration complete\n");
fflush(stdout);
@@ -249,7 +251,7 @@ inst_code inst_handle_calibrate(
break;
case inst_calc_man_ref_white:
- printf("Place the instrument on its reflective white reference %s,\n",id);
+ printf("Place the instrument on its reflective white reference S/N %s,\n",id);
printf(" and then hit any key to continue,\n");
break;
@@ -448,12 +450,12 @@ inst2_capability inst_show_disptype_options(FILE *fp, char *oline, icompaths *ic
olen = strlen(oline); /* lenth of option part of line */
- for (i = 0; icmps != NULL && i < icmps->npaths; i++) {
+ for (i = 0; icmps != NULL && i < icmps->ndpaths[dtix_inst]; i++) {
inst *it;
inst2_capability cap;
int k;
- if ((it = new_inst(icmps->paths[i], 1, g_log, NULL, NULL)) == NULL) {
+ if ((it = new_inst(icmps->dpaths[dtix_inst][i], 1, g_log, NULL, NULL)) == NULL) {
notall = 1;
continue;
}
diff --git a/spectro/instlib.ksh b/spectro/instlib.ksh
index 88796f8..8b0303f 100644
--- a/spectro/instlib.ksh
+++ b/spectro/instlib.ksh
@@ -42,6 +42,7 @@ RSPL_FILES="
SPECTRO_FILES="
License2.txt
+ spotread.c
Makefile.OSX
Makefile.UNIX
Makefile.WNT
@@ -49,6 +50,8 @@ SPECTRO_FILES="
pollem.c
conv.h
conv.c
+ sa_conv.h
+ sa_conv.c
aglob.c
aglob.h
hidio.h
@@ -56,13 +59,13 @@ SPECTRO_FILES="
icoms.h
inst.h
inst.c
- disptechs.h
- disptechs.c
insttypes.c
insttypes.h
insttypeinst.h
instappsup.c
instappsup.h
+ disptechs.h
+ disptechs.c
dtp20.c
dtp20.h
dtp22.c
@@ -101,6 +104,11 @@ SPECTRO_FILES="
specbos.c
kleink10.h
kleink10.c
+ ex1.c
+ ex1.h
+ smcube.h
+ smcube.c
+ cubecal.h
oemarch.c
oemarch.h
oeminst.c
@@ -118,10 +126,14 @@ SPECTRO_FILES="
usbio_nt.c
usbio_ox.c
usbio_lx.c
- usbio_bsd.c
+ rspec.h
+ rspec.c
xdg_bds.c
xdg_bds.h
- spotread.c
+ base64.h
+ base64.c
+ xrga.h
+ xrga.c
"
FILES=" $H_FILES $CGATS_FILES $NUMLIB_FILES $RSPL_FILES $XICC_FILES $SPECTRO_FILES "
@@ -138,7 +150,7 @@ for j in $FILES
do
if [ ! -e ${j} ] ; then
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!! Can't find file ${j} !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
- NOTFOUND="$NOTFOUND ${tt}"
+ NOTFOUND="$NOTFOUND ${j}"
else
cp ${j} _zipdir/instlib/${j##*/}
echo instlib/${j##*/} >> _ziplist
diff --git a/spectro/insttypeinst.h b/spectro/insttypeinst.h
index ad8047d..081d130 100644
--- a/spectro/insttypeinst.h
+++ b/spectro/insttypeinst.h
@@ -9,6 +9,10 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
#ifdef ENABLE_SERIAL
# include "dtp22.h"
diff --git a/spectro/insttypes.c b/spectro/insttypes.c
index 5a660a8..760d678 100644
--- a/spectro/insttypes.c
+++ b/spectro/insttypes.c
@@ -1,5 +1,5 @@
- /* Instrument supported types utilities */
+/* Instrument supported types utilities */
/*
* Argyll Color Correction System
@@ -37,6 +37,65 @@
/* Utility functions */
+/* Given a device type, return the corrsponding */
+/* category */
+extern icom_type inst_category(instType itype) {
+ switch (itype) {
+
+ /* Color measurement instruments */
+ case instDTP22:
+ case instDTP41:
+ case instDTP51:
+ case instSpectrolino:
+ case instSpectroScan:
+ case instSpectroScanT:
+ case instSpectrocam:
+ case instSpecbos1201:
+ case instSpecbos:
+ case instSpectraval:
+ case instKleinK10:
+ case instSMCube:
+ case instDTP20:
+ case instDTP92:
+ case instDTP94:
+ case instI1Disp1:
+ case instI1Disp2:
+ case instI1Disp3:
+ case instI1Monitor:
+ case instI1Pro:
+ case instI1Pro2:
+ case instColorMunki:
+ case instHCFR:
+ case instSpyder1:
+ case instSpyder2:
+ case instSpyder3:
+ case instSpyder4:
+ case instSpyder5:
+ case instHuey:
+ case instSmile:
+ case instEX1:
+ case instColorHug:
+ case instColorHug2:
+
+
+ return icomt_instrument;
+
+ /* 3D cLUT box */
+
+ /* Video test patern generator box */
+
+ /* Printers */
+ case devEpsonR1800:
+ return icomt_printer;
+
+ case instFakeDisp:
+ return icomt_unknown; // ???
+
+ }
+
+ return icomt_cat_any;
+}
+
/* Return the short instrument identification name (static string) */
char *inst_sname(instType itype) {
switch (itype) {
@@ -94,6 +153,8 @@ char *inst_sname(instType itype) {
return "specbos 1201";
case instSpecbos:
return "specbos";
+ case instSpectraval:
+ return "spectraval";
case instKleinK10:
return "K-10";
case instEX1:
@@ -104,6 +165,7 @@ char *inst_sname(instType itype) {
return "ColorHug";
case instColorHug2:
return "ColorHug2";
+
default:
break;
}
@@ -167,6 +229,8 @@ char *inst_name(instType itype) {
return "JETI specbos 1201";
case instSpecbos:
return "JETI specbos";
+ case instSpectraval:
+ return "JETI spectraval";
case instKleinK10:
return "Klein K-10";
case instEX1:
@@ -177,6 +241,7 @@ char *inst_name(instType itype) {
return "Hughski ColorHug";
case instColorHug2:
return "Hughski ColorHug2";
+
default:
break;
}
@@ -258,6 +323,8 @@ instType inst_enum(char *name) {
return instSpecbos1201;
else if (strcmp(name, "JETI specbos") == 0)
return instSpecbos;
+ else if (strcmp(name, "JETI spectraval") == 0)
+ return instSpectraval;
else if (strcmp(name, "Klein K-10") == 0)
return instKleinK10;
else if (strcmp(name, "Image Engineering EX1") == 0)
@@ -445,6 +512,7 @@ int inst_illuminant(xspect *sp, instType itype) {
case instSpecbos1201:
case instSpecbos:
+ case instSpectraval:
return 1; /* Not applicable */
case instKleinK10:
@@ -456,6 +524,7 @@ int inst_illuminant(xspect *sp, instType itype) {
case instSMCube:
return 1; /* Not applicable */
+
case instColorHug:
case instColorHug2:
return 1; /* Not applicable */
diff --git a/spectro/insttypes.h b/spectro/insttypes.h
index ab80cd2..8306bc8 100644
--- a/spectro/insttypes.h
+++ b/spectro/insttypes.h
@@ -1,7 +1,7 @@
#ifndef INSTTYPES_H
- /* Instrument suported types utilities. */
+/* Device and Instrument suported types definitions. */
/*
* Argyll Color Correction System
@@ -23,9 +23,11 @@
/* ----------------------------- */
-/* Possible types of instruments */
+/* Possible types of devices and instruments */
typedef enum {
- instUnknown = 0, /* Undefined Instrument */
+ devUnknown = 0, /* Undefined Device */
+
+ /* Color measurement instruments */
instDTP22, /* Xrite DTP22 (Digital Swatchbook) */
instDTP41, /* Xrite DTP41 */
instDTP51, /* Xrite DTP51 */
@@ -35,6 +37,7 @@ typedef enum {
instSpectrocam, /* Avantes Spectrocam */
instSpecbos1201, /* JETI specbos 1201 */
instSpecbos, /* JETI specbos XXXX */
+ instSpectraval, /* JETI spectraval 1501, 1511 */
instKleinK10, /* Klein K10-A */
instSMCube, /* SwatchMate Cube */
instDTP20, /* Xrite DTP20 (Pulse) */
@@ -62,12 +65,33 @@ typedef enum {
instFakeDisp = 9998, /* Fake display & instrument device id */
-} instType;
+ /* 3D cLUT box */
+ // 20000
+
+ /* Video test patern generator box */
+ // 30000
+
+ /* Printers */
+ devEpsonR1800 = 40000 /* Epson R1800 printer */
-struct _icoms; /* Forward declaration */
+} devType;
+
+/* Aliases for backwards compatibility */
+#define instUnknown devUnknown
+typedef devType instType;
+typedef devType cLUTType;
+typedef devType vtpgType;
+typedef devType printerType;
+
+struct _icoms; /* Forward declarations */
+enum _icom_type;
/* Utility functions in libinsttypes */
+/* Given a device type, return the corrsponding */
+/* category */
+//extern _icom_type inst_category(instType itype);
+
/* Given its instrument type, return the matching */
/* short instrument name (static string), */
extern char *inst_sname(instType itype);
diff --git a/spectro/iusb.h b/spectro/iusb.h
index a254ec0..94047cf 100644
--- a/spectro/iusb.h
+++ b/spectro/iusb.h
@@ -10,6 +10,10 @@
* see the License2.txt file for licencing details.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Device and/or Interface Class codes */
#define IUSB_CLASS_PER_INTERFACE 0x00 /* for DeviceClass */
#define IUSB_CLASS_AUDIO 0x01
@@ -127,5 +131,9 @@
#define IUSB_DEVICE_STATUS_REMOTE_WAKEUP 0x0002
#define IUSB_ENDPOINT_STATUS_HALT 0x0001
+#ifdef __cplusplus
+ }
+#endif
+
#define _IUSB_H_
#endif /* _IUSB_H_ */
diff --git a/spectro/kleink10.c b/spectro/kleink10.c
index 9599972..3d67b6c 100644
--- a/spectro/kleink10.c
+++ b/spectro/kleink10.c
@@ -369,8 +369,7 @@ k10_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
amutex_lock(p->lock);
- if (p->icom->port_type(p->icom) != icomt_serial
- && p->icom->port_type(p->icom) != icomt_usbserial) {
+ if (!(p->icom->port_type(p->icom) & icomt_serial)) {
amutex_unlock(p->lock);
a1logd(p->log, 1, "k10_init_coms: wrong communications type for device!\n");
return inst_coms_fail;
@@ -386,7 +385,8 @@ k10_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
if (brt[i] == baud_nc) {
i = 0;
}
- a1logd(p->log, 5, "k10_init_coms: trying baud ix %d\n",brt[i]);
+ a1logd(p->log, 5, "k10_init_coms: Trying %s baud, %d msec to go\n",
+ baud_rate_to_str(brt[i]), etime- msec_time());
if ((se = p->icom->set_ser_port(p->icom, fc_HardwareDTR, brt[i], parity_none,
stop_1, length_8)) != ICOM_OK) {
amutex_unlock(p->lock);
@@ -397,7 +397,7 @@ k10_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Check instrument is responding */
if (((ev = k10_command(p, "P0\r", buf, MAX_MES_SIZE, NULL, 21, ec_ec, 0.5)) & inst_mask)
!= inst_coms_fail) {
- break; /* We've got coms or user abort */
+ goto got_coms; /* We've got coms or user abort */
}
/* Check for user abort */
@@ -411,11 +411,12 @@ k10_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
}
- if (msec_time() >= etime) { /* We haven't established comms */
- amutex_unlock(p->lock);
- a1logd(p->log, 2, "k10_init_coms: failed to establish coms\n");
- return inst_coms_fail;
- }
+ /* We haven't established comms */
+ amutex_unlock(p->lock);
+ a1logd(p->log, 2, "k10_init_coms: failed to establish coms\n");
+ return inst_coms_fail;
+
+ got_coms:;
/* Check the response */
if (ev != inst_ok) {
@@ -2255,6 +2256,7 @@ inst_code k10_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
kleink10 *p = (kleink10 *)pp;
@@ -2267,6 +2269,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = k10_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -2738,8 +2741,7 @@ double mtx[3][3]
* error if it hasn't been initialised.
*/
static inst_code
-k10_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+k10_get_set_opt(inst *pp, inst_opt_type m, ...) {
kleink10 *p = (kleink10 *)pp;
char buf[MAX_MES_SIZE];
int se;
@@ -2753,6 +2755,11 @@ k10_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
/* Get target light state */
if (m == inst_opt_get_target_state) {
va_list args;
@@ -2821,12 +2828,17 @@ k10_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- if (!p->gotcoms)
- return inst_no_coms;
- if (!p->inited)
- return inst_no_init;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
- return inst_unsupported;
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/kleink10.h b/spectro/kleink10.h
index 4dcc334..136476a 100644
--- a/spectro/kleink10.h
+++ b/spectro/kleink10.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define K10_INTERNAL_ERROR 0xff01 /* Internal software error */
#define K10_TIMEOUT 0xff02 /* Communication timeout */
@@ -116,6 +120,9 @@ struct _kleink10 {
/* Constructor */
extern kleink10 *new_kleink10(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define KLEINK10_H
#endif /* KLEINK10_H */
diff --git a/spectro/linear.cal b/spectro/linear.cal
index 9c88605..b5e06c0 100644
--- a/spectro/linear.cal
+++ b/spectro/linear.cal
@@ -2,7 +2,7 @@ CAL
DESCRIPTOR "Argyll Device Calibration Curves"
ORIGINATOR "Argyll synthcal"
-CREATED "Mon Oct 26 01:10:48 2015"
+CREATED "Wed Sep 28 02:35:54 2016"
DEVICE_CLASS "DISPLAY"
COLOR_REP "RGB"
diff --git a/spectro/madvrwin.c b/spectro/madvrwin.c
index e131e5e..305a240 100644
--- a/spectro/madvrwin.c
+++ b/spectro/madvrwin.c
@@ -215,8 +215,11 @@ static ramdac *madvrwin_get_ramdac(dispwin *p) {
debugr("madvrwin_get_ramdac failed on malloc()\n");
return NULL;
}
- r->pdepth = p->pdepth;
- r->nent = (1 << p->pdepth);
+ r->fdepth = p->fdepth;
+ r->rdepth = p->rdepth;
+ r->ndepth = p->ndepth;
+ r->nent = p->nent;
+
r->clone = dispwin_clone_ramdac;
r->setlin = dispwin_setlin_ramdac;
r->del = dispwin_del_ramdac;
@@ -506,8 +509,15 @@ int ddebug /* >0 to print debug statements to stderr */
dispwin_set_default_delays(p);
- p->pdepth = 8; /* Assume this */
- p->edepth = 16;
+ p->fdepth = 8; /* Assume this */
+ p->rdepth = p->fdepth; /* Assumed */
+ p->ndepth = p->rdepth; /* Assumed */
+#ifdef ENABLE_RAMDAC
+ p->nent = (1 << p->ndepth);
+#else
+ p->nent = 0; /* No ramdac */
+#endif
+ p->edepth = 16; /* Assumed */
if (initMadVR(p)) {
debugr2((errout,"Failed to locate MadVR .dll or functions\n"));
@@ -515,7 +525,7 @@ int ddebug /* >0 to print debug statements to stderr */
return NULL;
}
- if (!madVR_BlindConnect(0, 1000)) {
+ if (!madVR_BlindConnect(1, 1000)) {
debugr2((errout,"Failed to connect to MadVR\n"));
free(p);
return NULL;
diff --git a/spectro/munki.c b/spectro/munki.c
index df54cd9..16cd863 100644
--- a/spectro/munki.c
+++ b/spectro/munki.c
@@ -71,8 +71,15 @@ static inst_code
munki_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
munki *p = (munki *) pp;
int se;
+#if defined(UNIX_X11)
+ /* Some Linux drivers fail to start every second time the device is opened */
+ /* if no clear halt is done on open, and some do the opposite. So */
+ /* reset after close to avoid the problem in all cases. */
+ icomuflags usbflags = icomuf_no_open_clear | icomuf_reset_before_close;
+#else
icomuflags usbflags = icomuf_none;
-#ifdef __APPLE__
+#endif
+#ifdef UNIX_APPLE
/* If the ColorMunki software has been installed, then there will */
/* be a daemon process that has the device open. Kill that process off */
/* so that we can open it here, before it re-spawns. */
@@ -82,10 +89,10 @@ munki_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
NULL
};
int retries = 20;
-#else /* !__APPLE__ */
+#else /* !UNIX_APPLE */
char **pnames = NULL;
int retries = 0;
-#endif /* !__APPLE__ */
+#endif /* !UNIX_APPLE */
a1logd(p->log, 2, "munki_init_coms: called\n");
@@ -98,6 +105,8 @@ munki_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Set config, interface, write end point, read end point, read quanta */
/* ("serial" end points aren't used - the Munki uses USB control messages) */
+ /* (The ColorMunki on Linux only starts every second time if we use the */
+ /* icomuf_no_open_clear flag.) */
if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, retries, pnames))
!= ICOM_OK) {
a1logd(p->log, 1, "munki_init_coms: failed ICOM err 0x%x\n",se);
@@ -368,6 +377,7 @@ static inst_code munki_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
munki *p = (munki *)pp;
@@ -378,7 +388,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
- rv = munki_imp_calibrate(p, calt, calc, id);
+ rv = munki_imp_calibrate(p, calt, calc, idtype, id);
return munki_interp_code(p, rv);
}
@@ -455,7 +465,7 @@ munki_interp_error(inst *pp, munki_code ec) {
case MUNKI_RD_TOOMANYPATCHES:
return "Too many patches";
case MUNKI_RD_NOTENOUGHSAMPLES:
- return "Not enough samples per patch";
+ return "Not enough samples per patch - Slow Down!";
case MUNKI_RD_NOFLASHES:
return "No flashes recognized";
case MUNKI_RD_NOAMBB4FLASHES:
@@ -797,6 +807,39 @@ munki_get_set_opt(inst *pp, inst_opt_type m, ...) {
return munki_interp_code(p, munki_set_scan_toll(p, toll_ratio));
}
+ /* Set xcalstd */
+ if (m == inst_opt_set_xcalstd) {
+ munkiimp *imp = (munkiimp *)p->m;
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ imp->target_calstd = standard;
+
+ return inst_ok;
+ }
+
+ /* Get the current effective xcalstd */
+ if (m == inst_opt_get_xcalstd) {
+ munkiimp *imp = (munkiimp *)p->m;
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (imp->target_calstd == xcalstd_native)
+ *standard = imp->native_calstd; /* If not overridden */
+ else
+ *standard = imp->target_calstd; /* Overidden std. */
+
+ return inst_ok;
+ }
+
if (!p->gotcoms)
return inst_no_coms;
if (!p->inited)
@@ -915,6 +958,33 @@ munki_get_set_opt(inst *pp, inst_opt_type m, ...) {
return inst_ok;
}
+ /* Return the white calibration tile spectrum */
+ /* (We always return the normal rez. reference values) */
+ if (m == inst_opt_get_cal_tile_sp) {
+ munkiimp *imp = (munkiimp *)p->m;
+ xspect *sp;
+ inst_code rv;
+ va_list args;
+ int i;
+
+ va_start(args, m);
+ sp = va_arg(args, xspect *);
+ va_end(args);
+
+ if (imp->white_ref1 == NULL)
+ return inst_no_init;
+
+ sp->spec_n = imp->nwav1;
+ sp->spec_wl_short = imp->wl_short1;
+ sp->spec_wl_long = imp->wl_long1;
+ sp->norm = 100.0;
+
+ for (i = 0; i < sp->spec_n; i++)
+ sp->spec[i] = imp->white_ref1[i] * 100.0;
+
+ return inst_ok;
+ }
+
/* Use default implementation of other inst_opt_type's */
{
inst_code rv;
diff --git a/spectro/munki_imp.c b/spectro/munki_imp.c
index 6f49d0d..eae2837 100644
--- a/spectro/munki_imp.c
+++ b/spectro/munki_imp.c
@@ -146,6 +146,7 @@
#include "munki.h"
#include "munki_imp.h"
+#include "xrga.h"
/* - - - - - - - - - - - - - - - - - - */
@@ -478,12 +479,27 @@ munki_code munki_imp_init(munki *p) {
unsigned char buf[4];
int calsize = 0, rucalsize;
unsigned char *calbuf; /* EEProm contents */
+ char *envv;
a1logd(p->log,2,"munki_init:\n");
if (p->itype != instColorMunki)
return MUNKI_UNKNOWN_MODEL;
+
+ m->native_calstd = xcalstd_xrga;
+ m->target_calstd = xcalstd_native; /* Default to native calibration standard*/
+
+ /* Honour Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ m->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ m->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ m->target_calstd = xcalstd_gmdi;
+ }
+
#ifdef ENABLE_SPOS_CHECK
m->nosposcheck = 0;
#else
@@ -523,7 +539,7 @@ munki_code munki_imp_init(munki *p) {
return ev;
/* Dump the eeprom contents as a block */
- if (p->log->debug >= 7) {
+ if (p->log->debug >= 9) {
int base, size;
a1logd(p->log,7, "EEPROM contents:\n");
@@ -960,6 +976,7 @@ munki_code munki_imp_calibrate(
munki *p,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+ inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
munki_code ev = MUNKI_OK;
@@ -1670,24 +1687,28 @@ if (ss->idark_int_time[j] != s->idark_int_time[j])
return MUNKI_CAL_SETUP;
}
} else if (*calt & inst_calt_em_dark) { /* Emissive Dark calib */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_cal_smode) {
*calc = inst_calc_man_cal_smode;
return MUNKI_CAL_SETUP;
}
} else if (*calt & inst_calt_trans_dark) { /* Transmissive dark */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_cal_smode) {
*calc = inst_calc_man_cal_smode;
return MUNKI_CAL_SETUP;
}
} else if (*calt & inst_calt_trans_vwhite) { /* Transmissive white for emulated trans. */
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_man_trans_white) {
*calc = inst_calc_man_trans_white;
return MUNKI_CAL_SETUP;
}
} else if (*calt & inst_calt_emis_int_time) {
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((*calc & inst_calc_cond_mask) != inst_calc_emis_white) {
*calc = inst_calc_emis_white;
@@ -1709,10 +1730,13 @@ if (ss->idark_int_time[j] != s->idark_int_time[j])
if (m->transwarn) {
*calc = inst_calc_message;
- if (m->transwarn & 2)
+ if (m->transwarn & 2) {
+ *idtype = inst_calc_id_trans_low;
strcpy(id, "Warning: Transmission light source is too low for accuracy!");
- else
+ } else {
+ *idtype = inst_calc_id_trans_wl;
strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
+ }
m->transwarn = 0;
return MUNKI_OK;
}
@@ -2259,8 +2283,13 @@ munki_code munki_imp_measure(
/* Indicate to the user that they can now scan the instrument, */
/* after a little delay that allows for the instrument reaction time. */
if (s->scan) {
- /* 100msec delay, 1KHz for 200 msec */
- msec_beep(0 + (int)(invsampt * 1000.0 + 0.9), 1000, 200);
+ int delay = 100 + (int)(invsampt * 1000.0 + 0.9);
+ if (p->eventcallback != NULL) {
+ issue_scan_ready((inst *)p, delay);
+ } else {
+ /* delay then 1KHz for 200 msec */
+ msec_beep(delay, 1000, 200);
+ }
}
/* Retry loop in case a display read is saturated */
@@ -5716,9 +5745,10 @@ munki_code munki_extract_patches_multimeas(
if (pat[k].use == 0)
continue;
- nno = (pat[k].no * 3)/4;
-// nno = (pat[k].no * 2)/3; // experimental tighter trim
- trim = (pat[k].no - nno)/2;
+// nno = (pat[k].no * 3 + 0)/4; /* Trim to 75% & round down */
+ nno = (pat[k].no * 2 + 0)/3; /* Trim to 66% & round down [def] */
+// nno = (pat[k].no * 2 + 0)/4; /* Trim to 50% & round down */
+ trim = (pat[k].no - nno + 1)/2;
pat[k].ss += trim;
pat[k].no = nno;
@@ -6257,6 +6287,8 @@ void munki_scale_specrd(
#define DO_CCDNORM /* [def] Normalise CCD values to original */
#define DO_CCDNORMAVG /* [und???] Normalise averages rather than per CCD bin */
+#define BOX_INTEGRATE /* [und] Integrate raw samples as if they were +/-0.5 boxes */
+ /* (This improves coeficient consistency a bit ?) */
#ifdef NEVER
/* Plot the matrix coefficients */
@@ -6918,7 +6950,7 @@ munki_code munki_create_hr(munki *p, int ref) {
if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
continue; /* Doesn't fall into this filter */
-#ifndef NEVER
+#ifdef BOX_INTEGRATE
/* Integrate in 0.05 nm increments from filter shape */
{
int nn;
@@ -7924,6 +7956,11 @@ munki_code munki_conv2XYZ(
}
conv->del(conv);
+
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, nvals, xcalstd_nonpol, m->target_calstd, m->native_calstd, clamp);
+
+
return MUNKI_OK;
}
diff --git a/spectro/munki_imp.h b/spectro/munki_imp.h
index ea9451f..f639395 100644
--- a/spectro/munki_imp.h
+++ b/spectro/munki_imp.h
@@ -177,6 +177,9 @@ struct _munkiimp {
double intclkp; /* Integration clock period (computed from tickdur) */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
/* Current state of hardware (~~99 are all these used ??) */
double c_inttime; /* Integration period (=inttime + deadtime) */
int c_measmodeflags; /* Measurement mode flags (set by trigger() */
@@ -418,6 +421,7 @@ munki_code munki_imp_calibrate(
munki *p,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[100] /* Condition identifier (ie. white reference ID) */
);
diff --git a/spectro/oemarch.c b/spectro/oemarch.c
index a9bbda1..be9abf3 100644
--- a/spectro/oemarch.c
+++ b/spectro/oemarch.c
@@ -38,6 +38,8 @@
#include <sys/param.h>
#include <sys/mount.h>
#include <ctype.h>
+#include <sys/types.h>
+#include <pwd.h>
#endif /* UNIX */
#ifndef SALONEINSTLIB
#include "copyright.h"
@@ -96,7 +98,7 @@ oem_target oemtargs = {
{ NULL }
}
#endif /* NT */
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
{ /* Installed files */
{ "/Applications/Spyder2express 2.2/Spyder2express.app/Contents/MacOSClassic/Spyder.lib", targ_spyd2_pld },
{ "/Applications/Spyder2pro 2.2/Spyder2pro.app/Contents/MacOSClassic/Spyder.lib", targ_spyd2_pld },
@@ -122,20 +124,29 @@ oem_target oemtargs = {
{ "/Installer/ColorMunkiDisplaySetup.exe", targ_i1d3_edr },
{ NULL }
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#ifdef UNIX_X11
{ /* Installed files */
{ NULL }
},
- { /* Volume names the CDROM may have */
+ { /* Volume names the CDROM may have. */
+ /* (It's a pity the linux developers have no idea what a stable API looks like...) */
+ { "/run/media/$USER/ColorVision", targ_spyd2_pld | targ_spyd_cal },
+ { "/run/media/$USER/Datacolor", targ_spyd2_pld | targ_spyd_cal },
+ { "/run/media/$USER/i1Profiler", targ_i1d3_edr },
+ { "/run/media/$USER/ColorMunki Displ", targ_i1d3_edr },
+
{ "/media/ColorVision", targ_spyd2_pld | targ_spyd_cal },
{ "/media/Datacolor", targ_spyd2_pld | targ_spyd_cal },
{ "/media/i1Profiler", targ_i1d3_edr },
{ "/media/ColorMunki Displ", targ_i1d3_edr },
+
{ "/mnt/cdrom", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
{ "/mnt/cdrecorder", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
+
{ "/media/cdrom", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
{ "/media/cdrecorder", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
+
{ "/cdrom", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
{ "/cdrecorder", targ_spyd2_pld | targ_spyd_cal | targ_i1d3_edr },
{ NULL }
@@ -152,14 +163,14 @@ oem_target oemtargs = {
#endif /* UNIX_X11 */
};
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
/* Global: */
char *oemamount_path = NULL;
#endif
/* Cleanup function for transfer on Apple OS X */
void oem_umiso() {
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
if (oemamount_path != NULL) {
char sbuf[MAXNAMEL+1 + 100];
sprintf(sbuf, "umount \"%s\"",oemamount_path);
@@ -167,7 +178,7 @@ void oem_umiso() {
sprintf(sbuf, "rmdir \"%s\"",oemamount_path);
system(sbuf);
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
}
static xfile *locate_volume(int verb);
@@ -561,7 +572,7 @@ static xfile *locate_volume(int verb) {
}
#endif /* NT */
-#if defined(__APPLE__)
+#if defined(UNIX_APPLE)
{
int j;
char tname[MAXNAMEL+1] = { '\000' };
@@ -626,7 +637,7 @@ static xfile *locate_volume(int verb) {
}
}
}
-#endif /* __APPLE__ */
+#endif /* UNIX_APPLE */
#if defined(UNIX_X11)
{
@@ -635,15 +646,49 @@ static xfile *locate_volume(int verb) {
/* See if we can see what we're looking for on one of the volumes */
/* It would be nice to be able to read the volume name ! */
for (j = 0;;j++) {
- if (oemtargs.volnames[j].path == NULL)
+ char *vol, *cp;
+
+ vol = oemtargs.volnames[j].path;
+
+ if (vol == NULL)
break;
- if (access(oemtargs.volnames[j].path, 0) == 0) {
- if (verb) printf("found '%s'\n",oemtargs.volnames[j].path);
- new_add_xf(&xf, oemtargs.volnames[j].path, NULL, 0,
- file_vol, oemtargs.volnames[j].ttype);
- break;
+ /* Some linux paths include the real user name */
+ if ((cp = strstr(vol, "$USER")) != NULL) {
+ char *ivol = vol;
+ char *usr;
+ int len;
+
+ /* Media gets mounted as console user, */
+ /* so we need to know what that is. */
+ /* (Hmm. this solves access problem when
+ running as root, but not saving resulting
+ file to $HOME/.local/etc */
+ if ((usr = getenv("SUDO_USER")) == NULL) {
+ if ((usr = getenv("USER")) == NULL)
+ error("$USER is empty");
+ }
+
+ len = strlen(ivol) - 5 + strlen(usr) + 1;
+
+ if ((vol = malloc(len)) == NULL)
+ error("Malloc of volume path length %d failed",len);
+
+ strncpy(vol, ivol, cp-ivol);
+ vol[cp-ivol]= '\000';
+ strcat(vol, usr);
+ strcat(vol, cp + 5);
+ }
+
+ if (access(vol, 0) == 0) {
+ if (verb) printf("found '%s'\n",vol);
+ new_add_xf(&xf, vol, NULL, 0, file_vol, oemtargs.volnames[j].ttype);
+ if (vol != oemtargs.volnames[j].path)
+ free(vol);
+ break;
}
+ if (vol != oemtargs.volnames[j].path)
+ free(vol);
}
}
#endif /* UNIX */
@@ -1407,7 +1452,7 @@ static xfile *edr_convert(xfile **pxf, xfile *xi, int verb) {
char *ccssname;
char *edrname;
unsigned char *buf;
- int len;
+ size_t len;
if (c->buf_write_ccss(c, &buf, &len)) {
error("Failed to create ccss for '%s' error '%s'",xi->name,c->err);
}
@@ -2622,7 +2667,8 @@ static xfile *ai_extract_cab(xfile **pxf, xfile *xi, char *tname, int verb) {
if (verb) printf("Extracted '%s' length %ld\n",xf->name,xf->len);
-save_xfile(xf, "temp.cab", NULL, verb);
+// /* Save diagnostic file */
+// save_xfile(xf, "temp.cab", NULL, verb);
return xf;
}
diff --git a/spectro/oeminst.c b/spectro/oeminst.c
index bce7a67..726a54c 100644
--- a/spectro/oeminst.c
+++ b/spectro/oeminst.c
@@ -20,6 +20,7 @@
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
+#include "ui.h"
#else /* SALONEINSTLIB */
#include <fcntl.h>
#include "sa_config.h"
@@ -33,7 +34,6 @@
#include "disptechs.h"
#include "ccmx.h"
#include "ccss.h"
-#include "ui.h"
void usage(void) {
fprintf(stderr,"Install OEM data files, Version %s\n",ARGYLL_VERSION_STR);
@@ -43,7 +43,7 @@ void usage(void) {
fprintf(stderr," -n Don't install, show where files would be installed\n");
fprintf(stderr," -c Don't install, save files to current directory\n");
fprintf(stderr," -S d Specify the install scope u = user (def.), l = local system]\n");
- fprintf(stderr," infile setup.exe CD install file(s) or .dll(s) containing install files\n");
+ fprintf(stderr," infile Manufacturers setup.exe install file(s) or .dll(s) containing install files\n");
fprintf(stderr," infile.[edr|ccss|ccmx] EDR file(s) to translate and install or CCSS or CCMX files to install\n");
fprintf(stderr," If no file is provided, oeminst will look for the install CD.\n");
exit(1);
diff --git a/spectro/pollem.c b/spectro/pollem.c
index f7578c8..855702b 100644
--- a/spectro/pollem.c
+++ b/spectro/pollem.c
@@ -1,5 +1,5 @@
- /* Unix serial I/O class poll() emulation. */
+/* Unix serial I/O class poll() emulation. */
/*
* Argyll Color Correction System
diff --git a/spectro/pollem.h b/spectro/pollem.h
index f8a86ee..bd879e1 100644
--- a/spectro/pollem.h
+++ b/spectro/pollem.h
@@ -1,7 +1,7 @@
#ifndef POLLEN_H
- /* Unix serial I/O class poll() emulation. */
+/* Unix serial I/O class poll() emulation. */
/*
* Argyll Color Correction System
diff --git a/spectro/rspec.c b/spectro/rspec.c
index e0e0194..6a7f8c7 100644
--- a/spectro/rspec.c
+++ b/spectro/rspec.c
@@ -28,6 +28,7 @@
#include <ctype.h>
#include <string.h>
#include <time.h>
+#include <fcntl.h>
#if defined(UNIX)
# include <utime.h>
#else
@@ -43,7 +44,9 @@
#include "sa_config.h"
#include "numsup.h"
#endif /* !SALONEINSTLIB */
-#include "plot.h"
+#ifndef SALONEINSTLIB
+# include "plot.h"
+#endif
#include "xspect.h"
#include "insttypes.h"
#include "conv.h"
@@ -51,6 +54,9 @@
#include "inst.h"
#include "rspec.h"
+#define BOX_INTEGRATE /* [und] Integrate raw samples as if they were +/-0.5 boxes */
+ /* (This improves coeficient consistency a bit ?) */
+
/* -------------------------------------------------- */
#if defined(__APPLE__) && defined(__POWERPC__)
@@ -250,6 +256,7 @@ void del_rspec(rspec *p) {
/* Plot the first rspec */
void plot_rspec1(rspec *p) {
+#ifndef SALONEINSTLIB
int i, no;
double xx[RSPEC_MAXSAMP];
double yy[RSPEC_MAXSAMP];
@@ -264,10 +271,12 @@ void plot_rspec1(rspec *p) {
yy[i] = p->samp[0][i];
}
do_plot(xx, yy, NULL, NULL, no);
+#endif
}
/* Plot the first rspec of 2 */
void plot_rspec2(rspec *p1, rspec *p2) {
+#ifndef SALONEINSTLIB
int i, no;
double xx[RSPEC_MAXSAMP];
double y1[RSPEC_MAXSAMP];
@@ -286,9 +295,11 @@ void plot_rspec2(rspec *p1, rspec *p2) {
y2[i] = p2->samp[0][i];
}
do_plot(xx, y1, y2, NULL, no);
+#endif
}
void plot_ecal(rspec_inf *inf) {
+#ifndef SALONEINSTLIB
int i, no;
double xx[RSPEC_MAXSAMP];
double yy[RSPEC_MAXSAMP];
@@ -303,6 +314,7 @@ void plot_ecal(rspec_inf *inf) {
yy[i] = inf->ecal[i];
}
do_plot(xx, yy, NULL, NULL, no);
+#endif
}
@@ -710,7 +722,7 @@ void rspec_make_resample_filters(rspec_inf *inf) {
a1logd(inf->log, 4,"rspec_make_resample_filters: maxcoeffs = %d\n",maxcoeffs);
- /* Figure out integration step size */
+ /* Figure out box integration step size */
#ifdef FAST_HIGH_RES_SETUP
finc = twidth/50.0;
if (rawspace/finc < 10.0)
@@ -754,6 +766,7 @@ void rspec_make_resample_filters(rspec_inf *inf) {
if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
continue; /* Doesn't fall into this filter */
+#ifdef BOX_INTEGRATE
/* Integrate in finc nm increments from filter shape */
/* using triangular integration. */
{
@@ -778,6 +791,9 @@ void rspec_make_resample_filters(rspec_inf *inf) {
lw = cw;
}
}
+#else
+ we = fabs(w2 - w1) * kernel(twidth, rwl);
+#endif
if (inf->fnocoef[j] >= maxcoeffs)
error("rspec_make_resample_filters: run out of high res filter space\n");
@@ -846,6 +862,7 @@ void rspec_make_resample_filters(rspec_inf *inf) {
/* Plot the wave resampling filters */
void plot_resample_filters(rspec_inf *inf) {
+#ifndef SALONEINSTLIB
double *xx, *ss;
double **yy;
int i, j, k, sx;
@@ -877,6 +894,7 @@ void plot_resample_filters(rspec_inf *inf) {
do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], inf->nraw);
free_dvector(xx, 0, inf->nraw-1);
free_dmatrix(yy, 0, 2, 0, inf->nraw-1);
+#endif
}
/* ================================================== */
diff --git a/spectro/sa_conv.c b/spectro/sa_conv.c
new file mode 100644
index 0000000..84286ba
--- /dev/null
+++ b/spectro/sa_conv.c
@@ -0,0 +1,865 @@
+
+#ifdef SALONEINSTLIB
+
+/*
+ * A very small subset of icclib, copied to here.
+ * This is just enough to support the standalone instruments
+ */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/97
+ *
+ * Copyright 1997 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include "sa_config.h"
+#include "numsup.h"
+#include "sa_conv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+sa_XYZNumber sa_D50 = {
+ 0.9642, 1.0000, 0.8249
+};
+
+sa_XYZNumber sa_D65 = {
+ 0.9505, 1.0000, 1.0890
+};
+
+sa_XYZNumber sa_D50_100 = {
+ 96.42, 100.00, 82.49
+};
+
+sa_XYZNumber sa_D65_100 = {
+ 95.05, 100.00, 108.90
+};
+
+unsigned int sa_CSSig2nchan(icColorSpaceSignature sig) {
+ switch(sig) {
+ case icSigXYZData:
+ return 3;
+ case icSigLabData:
+ return 3;
+ case icSigLuvData:
+ return 3;
+ case icSigYCbCrData:
+ return 3;
+ case icSigYxyData:
+ return 3;
+ case icSigRgbData:
+ return 3;
+ case icSigGrayData:
+ return 1;
+ case icSigHsvData:
+ return 3;
+ case icSigHlsData:
+ return 3;
+ case icSigCmykData:
+ return 4;
+ case icSigCmyData:
+ return 3;
+ case icSig2colorData:
+ return 2;
+ case icSig3colorData:
+ return 3;
+ case icSig4colorData:
+ return 4;
+ case icSig5colorData:
+ case icSigMch5Data:
+ return 5;
+ case icSig6colorData:
+ case icSigMch6Data:
+ return 6;
+ case icSig7colorData:
+ case icSigMch7Data:
+ return 7;
+ case icSig8colorData:
+ case icSigMch8Data:
+ return 8;
+ case icSig9colorData:
+ return 9;
+ case icSig10colorData:
+ return 10;
+ case icSig11colorData:
+ return 11;
+ case icSig12colorData:
+ return 12;
+ case icSig13colorData:
+ return 13;
+ case icSig14colorData:
+ return 14;
+ case icSig15colorData:
+ return 15;
+
+#ifdef NEVER
+ /* Non-standard and Pseudo spaces */
+ case icmSigYData:
+ return 1;
+ case icmSigLData:
+ return 1;
+ case icmSigL8Data:
+ return 1;
+ case icmSigLV2Data:
+ return 1;
+ case icmSigLV4Data:
+ return 1;
+ case icmSigPCSData:
+ return 3;
+ case icmSigLab8Data:
+ return 3;
+ case icmSigLabV2Data:
+ return 3;
+ case icmSigLabV4Data:
+ return 3;
+#endif /* NEVER */
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+void sa_SetUnity3x3(double mat[3][3]) {
+ int i, j;
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ if (i == j)
+ mat[j][i] = 1.0;
+ else
+ mat[j][i] = 0.0;
+ }
+ }
+
+}
+
+void sa_Cpy3x3(double dst[3][3], double src[3][3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src[j][i];
+ }
+}
+
+void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]) {
+ double tt[3];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
+ tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]) {
+ int i, j, k;
+ double td[3][3]; /* Temporary dest */
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ double tt = 0.0;
+ for (k = 0; k < 3; k++)
+ tt += src1[j][k] * src2[k][i];
+ td[j][i] = tt;
+ }
+ }
+
+ /* Copy result out */
+ for (j = 0; j < 3; j++)
+ for (i = 0; i < 3; i++)
+ dst[j][i] = td[j][i];
+}
+
+
+/* Matrix Inversion by Richard Carling from "Graphics Gems", Academic Press, 1990 */
+#define det2x2(a, b, c, d) (a * d - b * c)
+
+static void adjoint(
+double out[3][3],
+double in[3][3]
+) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+
+ /* assign to individual variable names to aid */
+ /* selecting correct values */
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ /* row column labeling reversed since we transpose rows & columns */
+
+ out[0][0] = det2x2(b2, b3, c2, c3);
+ out[1][0] = - det2x2(a2, a3, c2, c3);
+ out[2][0] = det2x2(a2, a3, b2, b3);
+
+ out[0][1] = - det2x2(b1, b3, c1, c3);
+ out[1][1] = det2x2(a1, a3, c1, c3);
+ out[2][1] = - det2x2(a1, a3, b1, b3);
+
+ out[0][2] = det2x2(b1, b2, c1, c2);
+ out[1][2] = - det2x2(a1, a2, c1, c2);
+ out[2][2] = det2x2(a1, a2, b1, b2);
+}
+
+static double sa_Det3x3(double in[3][3]) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+ double ans;
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ ans = a1 * det2x2(b2, b3, c2, c3)
+ - b1 * det2x2(a2, a3, c2, c3)
+ + c1 * det2x2(a2, a3, b2, b3);
+ return ans;
+}
+
+#define SA__SMALL_NUMBER 1.e-8
+
+int sa_Inverse3x3(double out[3][3], double in[3][3]) {
+ int i, j;
+ double det;
+
+ /* calculate the 3x3 determinant
+ * if the determinant is zero,
+ * then the inverse matrix is not unique.
+ */
+ det = sa_Det3x3(in);
+
+ if ( fabs(det) < SA__SMALL_NUMBER)
+ return 1;
+
+ /* calculate the adjoint matrix */
+ adjoint(out, in);
+
+ /* scale the adjoint matrix to get the inverse */
+ for (i = 0; i < 3; i++)
+ for(j = 0; j < 3; j++)
+ out[i][j] /= det;
+ return 0;
+}
+
+#undef SA__SMALL_NUMBER
+#undef det2x2
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Transpose a 3x3 matrix */
+void sa_Transpose3x3(double out[3][3], double in[3][3]) {
+ int i, j;
+ if (out != in) {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = in[j][i];
+ } else {
+ double tt[3][3];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ tt[i][j] = in[j][i];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = tt[i][j];
+ }
+}
+
+/* Scale a 3 vector by the given ratio */
+void sa_Scale3(double out[3], double in[3], double rat) {
+ out[0] = in[0] * rat;
+ out[1] = in[1] * rat;
+ out[2] = in[2] * rat;
+}
+
+/* Clamp a 3 vector to be +ve */
+void sa_Clamp3(double out[3], double in[3]) {
+ int i;
+ for (i = 0; i < 3; i++)
+ out[i] = in[i] < 0.0 ? 0.0 : in[i];
+}
+
+/* Return the normal Delta E given two Lab values */
+double sa_LabDE(double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ rv += tt * tt;
+
+ return sqrt(rv);
+}
+
+/* Return the CIE94 Delta E color difference measure, squared */
+double sa_CIE94sq(double Lab0[3], double Lab1[3]) {
+ double desq, dhsq;
+ double dlsq, dcsq;
+ double c12;
+
+ {
+ double dl, da, db;
+ dl = Lab0[0] - Lab1[0];
+ dlsq = dl * dl; /* dl squared */
+ da = Lab0[1] - Lab1[1];
+ db = Lab0[2] - Lab1[2];
+
+ /* Compute normal Lab delta E squared */
+ desq = dlsq + da * da + db * db;
+ }
+
+ {
+ double c1, c2, dc;
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ c2 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ c12 = sqrt(c1 * c2); /* Symetric chromanance */
+
+ /* delta chromanance squared */
+ dc = c1 - c2;
+ dcsq = dc * dc;
+ }
+
+ /* Compute delta hue squared */
+ if ((dhsq = desq - dlsq - dcsq) < 0.0)
+ dhsq = 0.0;
+ {
+ double sc, sh;
+
+ /* Weighting factors for delta chromanance & delta hue */
+ sc = 1.0 + 0.045 * c12;
+ sh = 1.0 + 0.015 * c12;
+ return dlsq + dcsq/(sc * sc) + dhsq/(sh * sh);
+ }
+}
+
+/* Return the CIE94 Delta E color difference measure */
+double sa_CIE94(double Lab0[3], double Lab1[3]) {
+ return sqrt(sa_CIE94sq(Lab0, Lab1));
+}
+
+/* Return the CIE94 Delta E color difference measure for two XYZ values */
+double sa_XYZCIE94(sa_XYZNumber *w, double *in0, double *in1) {
+ double lab0[3], lab1[3];
+
+ sa_XYZ2Lab(w, lab0, in0);
+ sa_XYZ2Lab(w, lab1, in1);
+ return sqrt(sa_CIE94sq(lab0, lab1));
+}
+
+/* CIE XYZ to perceptual CIE 1976 L*a*b* */
+void
+sa_XYZ2Lab(sa_XYZNumber *w, double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/w->X;
+ y = Y/w->Y;
+ z = Z/w->Z;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+void sa_Lab2XYZ(sa_XYZNumber *w, double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+
+ fy = (L + 16.0)/116.0;
+ fx = a/500.0 + fy;
+ fz = fy - b/200.0;
+
+ if (fy > 24.0/116.0)
+ y = pow(fy,3.0);
+ else
+ y = (fy - 16.0/116.0)/7.787036979;
+
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ out[0] = x * w->X;
+ out[1] = y * w->Y;
+ out[2] = z * w->Z;
+}
+
+
+void sa_Yxy2XYZ(double *out, double *in) {
+ double Y = in[0];
+ double x = in[1];
+ double y = in[2];
+ double z = 1.0 - x - y;
+ double sum;
+ if (y < 1e-9) {
+ out[0] = out[1] = out[2] = 0.0;
+ } else {
+ sum = Y/y;
+ out[0] = x * sum;
+ out[1] = Y;
+ out[2] = z * sum;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Object for computing RFC 1321 MD5 checksums. */
+/* Derived from Colin Plumb's 1993 public domain code. */
+
+/* Reset the checksum */
+static void sa_MD5_reset(sa_MD5 *p) {
+ p->tlen = 0;
+
+ p->sum[0] = 0x67452301;
+ p->sum[1] = 0xefcdab89;
+ p->sum[2] = 0x98badcfe;
+ p->sum[3] = 0x10325476;
+
+ p->fin = 0;
+}
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, pp, xtra, s) \
+ data = (pp)[0] + ((pp)[3] << 24) + ((pp)[2] << 16) + ((pp)[1] << 8); \
+ w += f(x, y, z) + data + xtra; \
+ w = (w << s) | (w >> (32-s)); \
+ w += x;
+
+/* Add another 64 bytes to the checksum */
+static void sa_MD5_accume(sa_MD5 *p, ORD8 *in) {
+ ORD32 data, a, b, c, d;
+
+ a = p->sum[0];
+ b = p->sum[1];
+ c = p->sum[2];
+ d = p->sum[3];
+
+ MD5STEP(F1, a, b, c, d, in + (4 * 0), 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 1), 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 2), 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 3), 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 4), 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 5), 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 6), 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 7), 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 8), 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 9), 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 10), 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 11), 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 12), 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 13), 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 14), 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 15), 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in + (4 * 1), 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 6), 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 11), 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 0), 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 5), 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 10), 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 15), 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 4), 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 9), 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 14), 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 3), 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 8), 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 13), 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 2), 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 7), 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 12), 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in + (4 * 5), 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 8), 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 11), 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 14), 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 1), 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 4), 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 7), 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 10), 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 13), 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 0), 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 3), 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 6), 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 9), 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 12), 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 15), 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 2), 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in + (4 * 0), 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 7), 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 14), 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 5), 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 12), 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 3), 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 10), 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 1), 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 8), 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 15), 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 6), 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 13), 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 4), 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 11), 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 2), 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 9), 0xeb86d391, 21);
+
+ p->sum[0] += a;
+ p->sum[1] += b;
+ p->sum[2] += c;
+ p->sum[3] += d;
+}
+
+#undef F1
+#undef F2
+#undef F3
+#undef F4
+#undef MD5STEP
+
+/* Add some bytes */
+static void sa_MD5_add(sa_MD5 *p, ORD8 *ibuf, unsigned int len) {
+ unsigned int bs;
+
+ if (p->fin)
+ return; /* This is actually an error */
+
+ bs = p->tlen; /* Current bytes added */
+ p->tlen = bs + len; /* Update length after adding this buffer */
+ bs &= 0x3f; /* Bytes already in buffer */
+
+ /* Deal with any existing partial bytes in p->buf */
+ if (bs) {
+ ORD8 *np = (ORD8 *)p->buf + bs; /* Next free location in partial buffer */
+
+ bs = 64 - bs; /* Free space in partial buffer */
+
+ if (len < bs) { /* Not enought new to make a full buffer */
+ memmove(np, ibuf, len);
+ return;
+ }
+
+ memmove(np, ibuf, bs); /* Now got one full buffer */
+ sa_MD5_accume(p, np);
+ ibuf += bs;
+ len -= bs;
+ }
+
+ /* Deal with input data 64 bytes at a time */
+ while (len >= 64) {
+ sa_MD5_accume(p, ibuf);
+ ibuf += 64;
+ len -= 64;
+ }
+
+ /* Deal with any remaining bytes */
+ memmove(p->buf, ibuf, len);
+}
+
+/* Finalise the checksum and return the result. */
+static void sa_MD5_get(sa_MD5 *p, ORD8 chsum[16]) {
+ int i;
+ unsigned count;
+ ORD32 bits1, bits0;
+ ORD8 *pp;
+
+ if (p->fin == 0) {
+
+ /* Compute number of bytes processed mod 64 */
+ count = p->tlen & 0x3f;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ pp = p->buf + count;
+ *pp++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64, allowing 8 bytes for length in bits. */
+ if (count < 8) { /* Not enough space for padding and length */
+
+ memset(pp, 0, count);
+ sa_MD5_accume(p, p->buf);
+
+ /* Now fill the next block with 56 bytes */
+ memset(p->buf, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(pp, 0, count - 8);
+ }
+
+ /* Compute number of bits */
+ bits1 = 0x7 & (p->tlen >> (32 - 3));
+ bits0 = p->tlen << 3;
+
+ /* Append number of bits */
+ p->buf[64 - 8] = bits0 & 0xff;
+ p->buf[64 - 7] = (bits0 >> 8) & 0xff;
+ p->buf[64 - 6] = (bits0 >> 16) & 0xff;
+ p->buf[64 - 5] = (bits0 >> 24) & 0xff;
+ p->buf[64 - 4] = bits1 & 0xff;
+ p->buf[64 - 3] = (bits1 >> 8) & 0xff;
+ p->buf[64 - 2] = (bits1 >> 16) & 0xff;
+ p->buf[64 - 1] = (bits1 >> 24) & 0xff;
+
+ sa_MD5_accume(p, p->buf);
+
+ p->fin = 1;
+ }
+
+ /* Return the result, lsb to msb */
+ pp = chsum;
+ for (i = 0; i < 4; i++) {
+ *pp++ = p->sum[i] & 0xff;
+ *pp++ = (p->sum[i] >> 8) & 0xff;
+ *pp++ = (p->sum[i] >> 16) & 0xff;
+ *pp++ = (p->sum[i] >> 24) & 0xff;
+ }
+}
+
+
+/* Delete the instance */
+static void sa_MD5_del(sa_MD5 *p) {
+
+ /* This object */
+ if (p != NULL)
+ free(p);
+}
+
+/* Create a new MD5 checksumming object, with a reset checksum value */
+/* Return it or NULL if there is an error */
+sa_MD5 *new_sa_MD5() {
+ sa_MD5 *p;
+
+ if ((p = (sa_MD5 *)calloc(1,sizeof(sa_MD5))) == NULL)
+ return NULL;
+
+ p->reset = sa_MD5_reset;
+ p->add = sa_MD5_add;
+ p->get = sa_MD5_get;
+ p->del = sa_MD5_del;
+
+ p->reset(p);
+
+ return p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A sub-set of ludecomp code from numlib */
+
+int sa_lu_decomp(double **a, int n, int *pivx, double *rip) {
+ int i, j;
+ double *rscale, RSCALE[10];
+
+ if (n <= 10)
+ rscale = RSCALE;
+ else
+ rscale = dvector(0, n-1);
+
+ for (i = 0; i < n; i++) {
+ double big;
+ for (big = 0.0, j=0; j < n; j++) {
+ double temp;
+ temp = fabs(a[i][j]);
+ if (temp > big)
+ big = temp;
+ }
+ if (fabs(big) <= DBL_MIN) {
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 1;
+ }
+ rscale[i] = 1.0/big;
+ }
+
+ for (*rip = 1.0, j = 0; j < n; j++) {
+ double big;
+ int k, bigi = 0;
+
+ for (i = 0; i < j; i++) {
+ double sum;
+ sum = a[i][j];
+ for (k = 0; k < i; k++)
+ sum -= a[i][k] * a[k][j];
+ a[i][j] = sum;
+ }
+
+ for (big = 0.0, i = j; i < n; i++) {
+ double sum, temp;
+ sum = a[i][j];
+ for (k = 0; k < j; k++)
+ sum -= a[i][k] * a[k][j];
+ a[i][j] = sum;
+ temp = rscale[i] * fabs(sum);
+ if (temp >= big) {
+ big = temp;
+ bigi = i;
+ }
+ }
+
+ if (j != bigi) {
+ {
+ double *temp;
+ temp = a[bigi];
+ a[bigi] = a[j];
+ a[j] = temp;
+ }
+ *rip = -(*rip);
+ rscale[bigi] = rscale[j];
+ }
+
+ pivx[j] = bigi;
+ if (fabs(a[j][j]) <= DBL_MIN) {
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 1;
+ }
+
+ if (j != (n-1)) {
+ double temp;
+ temp = 1.0/a[j][j];
+ for (i = j+1; i < n; i++)
+ a[i][j] *= temp;
+ }
+ }
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 0;
+}
+
+void sa_lu_backsub(double **a, int n, int *pivx, double *b) {
+ int i, j;
+ int nvi;
+
+ for (nvi = -1, i = 0; i < n; i++) {
+ int px;
+ double sum;
+
+ px = pivx[i];
+ sum = b[px];
+ b[px] = b[i];
+ if (nvi >= 0) {
+ for (j = nvi; j < i; j++)
+ sum -= a[i][j] * b[j];
+ } else {
+ if (sum != 0.0)
+ nvi = i;
+ }
+ b[i] = sum;
+ }
+
+ for (i = (n-1); i >= 0; i--) {
+ double sum;
+ sum = b[i];
+ for (j = i+1; j < n; j++)
+ sum -= a[i][j] * b[j];
+ b[i] = sum/a[i][i];
+ }
+}
+
+int sa_lu_invert(double **a, int n) {
+ int i, j;
+ double rip;
+ int *pivx, PIVX[10];
+ double **y;
+
+ if (n <= 10)
+ pivx = PIVX;
+ else
+ pivx = ivector(0, n-1);
+
+ if (sa_lu_decomp(a, n, pivx, &rip)) {
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 1;
+ }
+
+ y = dmatrix(0, n-1, 0, n-1);
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++) {
+ y[i][j] = a[i][j];
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++)
+ a[i][j] = 0.0;
+ a[i][i] = 1.0;
+ sa_lu_backsub(y, n, pivx, a[i]);
+ }
+
+ free_dmatrix(y, 0, n-1, 0, n-1);
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+
+ return 0;
+}
+
+int sa_lu_psinvert(double **out, double **in, int m, int n) {
+ int rv = 0;
+ double **tr;
+ double **sq;
+
+ tr = dmatrix(0, n-1, 0, m-1);
+ matrix_trans(tr, in, m, n);
+
+ if (m > n) {
+ sq = dmatrix(0, n-1, 0, n-1);
+ if ((rv = matrix_mult(sq, n, n, tr, n, m, in, m, n)) == 0) {
+ if ((rv = sa_lu_invert(sq, n)) == 0) {
+ rv = matrix_mult(out, n, m, sq, n, n, tr, n, m);
+ }
+ }
+ free_dmatrix(sq, 0, n-1, 0, n-1);
+ } else {
+ sq = dmatrix(0, m-1, 0, m-1);
+ if ((rv = matrix_mult(sq, m, m, in, m, n, tr, n, m)) == 0) {
+ if ((rv = sa_lu_invert(sq, m)) == 0) {
+ rv = matrix_mult(out, n, m, tr, n, m, sq, m, m);
+ }
+ }
+ free_dmatrix(sq, 0, m-1, 0, m-1);
+ }
+
+ free_dmatrix(tr, 0, n-1, 0, m-1);
+ return rv;
+}
+
+
+#endif /* SALONEINSTLIB */
+
+
diff --git a/spectro/sa_conv.h b/spectro/sa_conv.h
new file mode 100644
index 0000000..0f7e635
--- /dev/null
+++ b/spectro/sa_conv.h
@@ -0,0 +1,233 @@
+#ifndef SA_CONV_H
+
+#ifdef SALONEINSTLIB
+/*
+ * A very small subset of icclib and numlib for the standalone instrument lib.
+ */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/2/9
+ *
+ * Copyright 1996 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from icoms.h
+ */
+
+#if defined (NT)
+# if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
+# if defined _WIN32_WINNT
+# undef _WIN32_WINNT
+# endif
+# define _WIN32_WINNT 0x0501
+# endif
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <io.h>
+#endif
+
+#if defined (UNIX)
+# include <unistd.h>
+# include <glob.h>
+# include <pthread.h>
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A subset of icclib */
+
+#ifndef MAX_CHAN
+# define MAX_CHAN 15
+#endif
+
+typedef enum {
+ sa_SigXYZData = 0x58595A20L, /* 'XYZ ' */
+ sa_SigLabData = 0x4C616220L, /* 'Lab ' */
+ sa_SigLuvData = 0x4C757620L, /* 'Luv ' */
+ sa_SigYCbCrData = 0x59436272L, /* 'YCbr' */
+ sa_SigYxyData = 0x59787920L, /* 'Yxy ' */
+ sa_SigRgbData = 0x52474220L, /* 'RGB ' */
+ sa_SigGrayData = 0x47524159L, /* 'GRAY' */
+ sa_SigHsvData = 0x48535620L, /* 'HSV ' */
+ sa_SigHlsData = 0x484C5320L, /* 'HLS ' */
+ sa_SigCmykData = 0x434D594BL, /* 'CMYK' */
+ sa_SigCmyData = 0x434D5920L, /* 'CMY ' */
+
+ sa_Sig2colorData = 0x32434C52L, /* '2CLR' */
+ sa_Sig3colorData = 0x33434C52L, /* '3CLR' */
+ sa_Sig4colorData = 0x34434C52L, /* '4CLR' */
+ sa_Sig5colorData = 0x35434C52L, /* '5CLR' */
+ sa_Sig6colorData = 0x36434C52L, /* '6CLR' */
+ sa_Sig7colorData = 0x37434C52L, /* '7CLR' */
+ sa_Sig8colorData = 0x38434C52L, /* '8CLR' */
+ sa_Sig9colorData = 0x39434C52L, /* '9CLR' */
+ sa_Sig10colorData = 0x41434C52L, /* 'ACLR' */
+ sa_Sig11colorData = 0x42434C52L, /* 'BCLR' */
+ sa_Sig12colorData = 0x43434C52L, /* 'CCLR' */
+ sa_Sig13colorData = 0x44434C52L, /* 'DCLR' */
+ sa_Sig14colorData = 0x45434C52L, /* 'ECLR' */
+ sa_Sig15colorData = 0x46434C52L, /* 'FCLR' */
+
+ sa_SigMch5Data = 0x4D434835L, /* 'MCH5' Colorsync ? */
+ sa_SigMch6Data = 0x4D434836L, /* 'MCH6' Hexachrome: CMYKOG */
+ sa_SigMch7Data = 0x4D434837L, /* 'MCH7' Colorsync ? */
+ sa_SigMch8Data = 0x4D434838L, /* 'MCH8' Colorsync ? */
+ sa_SigNamedData = 0x6e6d636cL, /* 'nmcl' ??? */
+
+ sa_MaxEnumData = -1
+} sa_ColorSpaceSignature;
+
+typedef enum {
+ sa_SigInputClass = 0x73636E72L, /* 'scnr' */
+ sa_SigDisplayClass = 0x6D6E7472L, /* 'mntr' */
+ sa_SigOutputClass = 0x70727472L, /* 'prtr' */
+ sa_SigLinkClass = 0x6C696E6BL, /* 'link' */
+ sa_SigAbstractClass = 0x61627374L, /* 'abst' */
+ sa_SigColorSpaceClass = 0x73706163L, /* 'spac' */
+ sa_SigNamedColorClass = 0x6e6d636cL, /* 'nmcl' */
+ sa_MaxEnumClass = -1
+} sa_ProfileClassSignature;
+
+typedef struct {
+ double X;
+ double Y;
+ double Z;
+} sa_XYZNumber;
+
+unsigned int sa_CSSig2nchan(sa_ColorSpaceSignature sig);
+extern sa_XYZNumber sa_D50;
+extern sa_XYZNumber sa_D65;
+extern sa_XYZNumber sa_D50_100;
+extern sa_XYZNumber sa_D65_100;
+void sa_SetUnity3x3(double mat[3][3]);
+void sa_Cpy3x3(double out[3][3], double mat[3][3]);
+void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]);
+void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]);
+int sa_Inverse3x3(double out[3][3], double in[3][3]);
+void sa_Transpose3x3(double out[3][3], double in[3][3]);
+void sa_Scale3(double out[3], double in[3], double rat);
+double sa_LabDE(double *in0, double *in1);
+double sa_CIE94sq(double *in0, double *in1);
+void sa_Lab2XYZ(sa_XYZNumber *w, double *out, double *in);
+void sa_XYZ2Lab(sa_XYZNumber *w, double *out, double *in);
+void sa_Yxy2XYZ(double *out, double *in);
+
+#define icColorSpaceSignature sa_ColorSpaceSignature
+#define icSigXYZData sa_SigXYZData
+#define icSigLabData sa_SigLabData
+#define icSigLuvData sa_SigLuvData
+#define icSigYCbCrData sa_SigYCbCrData
+#define icSigYxyData sa_SigYxyData
+#define icSigRgbData sa_SigRgbData
+#define icSigGrayData sa_SigGrayData
+#define icSigHsvData sa_SigHsvData
+#define icSigHlsData sa_SigHlsData
+#define icSigCmykData sa_SigCmykData
+#define icSigCmyData sa_SigCmyData
+#define icSig2colorData sa_Sig2colorData
+#define icSig3colorData sa_Sig3colorData
+#define icSig4colorData sa_Sig4colorData
+#define icSig5colorData sa_Sig5colorData
+#define icSig6colorData sa_Sig6colorData
+#define icSig7colorData sa_Sig7colorData
+#define icSig8colorData sa_Sig8colorData
+#define icSig9colorData sa_Sig9colorData
+#define icSig10colorData sa_Sig10colorData
+#define icSig11colorData sa_Sig11colorData
+#define icSig12colorData sa_Sig12colorData
+#define icSig13colorData sa_Sig13colorData
+#define icSig14colorData sa_Sig14colorData
+#define icSig15colorData sa_Sig15colorData
+#define icSigMch5Data sa_SigMch5Data
+#define icSigMch6Data sa_SigMch6Data
+#define icSigMch7Data sa_SigMch7Data
+#define icSigMch8Data sa_SigMch8Data
+#define icSigNamedData sa_SigNamedData
+#define icMaxEnumData sa_MaxEnumData
+
+#define icProfileClassSignature sa_ProfileClassSignature
+#define icSigInputClass sa_SigInputClass
+#define icSigDisplayClass sa_SigDisplayClass
+#define icSigOutputClass sa_SigOutputClass
+#define icSigLinkClass sa_SigLinkClass
+#define icSigAbstractClass sa_SigAbstractClass
+#define icSigColorSpaceClass sa_SigColorSpaceClass
+#define icSigNamedColorClass sa_SigNamedColorClass
+
+#define icmCSSig2nchan sa_CSSig2nchan
+
+#define icmXYZNumber sa_XYZNumber
+#define icmD50 sa_D50
+#define icmD65 sa_D65
+#define icmD50_100 sa_D50_100
+#define icmD65_100 sa_D65_100
+
+#define icmSetUnity3x3 sa_SetUnity3x3
+#define icmCpy3x3 sa_Cpy3x3
+#define icmMulBy3x3 sa_MulBy3x3
+#define icmMul3x3_2 sa_Mul3x3_2
+#define icmInverse3x3 sa_Inverse3x3
+#define icmTranspose3x3 sa_Transpose3x3
+
+#define icmCpy3(d_ary, s_ary) ((d_ary)[0] = (s_ary)[0], (d_ary)[1] = (s_ary)[1], \
+ (d_ary)[2] = (s_ary)[2])
+#define icmScale3 sa_Scale3
+#define icmClamp3 sa_Clamp3
+
+#define icmAry2XYZ(xyz, ary) ((xyz).X = (ary)[0], (xyz).Y = (ary)[1], (xyz).Z = (ary)[2])
+
+#define icmLabDE sa_LabDE
+#define icmCIE94sq sa_CIE94sq
+#define icmXYZ2Lab sa_XYZ2Lab
+#define icmLab2XYZ sa_Lab2XYZ
+#define icmYxy2XYZ sa_Yxy2XYZ
+
+/* A helper object that computes MD5 checksums */
+struct _sa_MD5 {
+ /* Private: */
+ int fin; /* Flag, nz if final has been called */
+ ORD32 sum[4]; /* Current/final checksum */
+ unsigned int tlen; /* Total length added in bytes */
+ ORD8 buf[64]; /* Partial buffer */
+
+ /* Public: */
+ void (*reset)(struct _sa_MD5 *p); /* Reset the checksum */
+ void (*add)(struct _sa_MD5 *p, ORD8 *buf, unsigned int len); /* Add some bytes */
+ void (*get)(struct _sa_MD5 *p, ORD8 chsum[16]); /* Finalise and get the checksum */
+ void (*del)(struct _sa_MD5 *p); /* We're done with the object */
+
+}; typedef struct _sa_MD5 sa_MD5;
+
+/* Create a new MD5 checksumming object, with a reset checksum value */
+/* Return it or NULL if there is an error. */
+extern sa_MD5 *new_sa_MD5(void);
+
+#define icmMD5 sa_MD5
+#define new_icmMD5 new_sa_MD5
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A subset of numlib */
+
+int sa_lu_psinvert(double **out, double **in, int m, int n);
+
+#define lu_psinvert sa_lu_psinvert
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* SALONEINSTLIB */
+
+#define SA_CONV_H
+#endif /* SA_CONV_H */
diff --git a/spectro/smcube.c b/spectro/smcube.c
index 8a788ec..c450d48 100644
--- a/spectro/smcube.c
+++ b/spectro/smcube.c
@@ -68,9 +68,10 @@
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
-#else /* !SALONEINSTLIB */
+#else /* SALONEINSTLIB */
#include "sa_config.h"
#include "numsup.h"
+#include "sa_conv.h"
#endif /* !SALONEINSTLIB */
#include "xspect.h"
#include "insttypes.h"
@@ -210,12 +211,13 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
a1logd(p->log, 2, "smcube_init_coms: About to init Serial I/O\n");
- if (p->icom->port_type(p->icom) != icomt_serial
- && p->icom->port_type(p->icom) != icomt_usbserial) {
- a1logd(p->log, 1, "smcube_init_coms: wrong communications type for device!\n");
+ if (!(p->icom->dctype & icomt_seriallike)
+ && !(p->icom->dctype & icomt_fastserial)) {
+ a1logd(p->log, 1, "smcube_init_coms: wrong communications type for device! (dctype 0x%x)\n",p->icom->dctype);
return inst_coms_fail;
}
+ /* Communications has already been established */
if (p->bt) {
amutex_lock(p->lock);
@@ -234,8 +236,8 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
amutex_unlock(p->lock);
+ /* We need to setup communications */
} else {
-
amutex_lock(p->lock);
/* The tick to give up on */
@@ -248,7 +250,8 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
if (brt[i] == baud_nc) {
i = 0;
}
- a1logd(p->log, 5, "smcube_init_coms: trying %s baud\n",baud_rate_to_str(brt[i]));
+ a1logd(p->log, 4, "smcube_init_coms: Trying %s baud, %d msec to go\n",
+ baud_rate_to_str(brt[i]), etime- msec_time());
if ((se = p->icom->set_ser_port(p->icom, fc_Hardware, brt[i], parity_none,
stop_1, length_8)) != ICOM_OK) {
amutex_unlock(p->lock);
@@ -260,7 +263,7 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
buf[0] = 0x7e, buf[1] = 0x00, buf[2] = 0x02, buf[3] = 0x00; /* Ping command */
if (((ev = smcube_command(p, buf, 4, buf, 4, DEFTO)) & inst_mask)
!= inst_coms_fail) {
- break; /* We've got coms or user abort */
+ goto got_coms; /* We've got coms or user abort */
}
/* Check for user abort */
@@ -274,11 +277,12 @@ smcube_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
}
- if (msec_time() >= etime) { /* We haven't established comms */
- amutex_unlock(p->lock);
- a1logd(p->log, 2, "smcube_init_coms: failed to establish coms\n");
- return inst_coms_fail;
- }
+ /* We haven't established comms */
+ amutex_unlock(p->lock);
+ a1logd(p->log, 2, "smcube_init_coms: failed to establish coms\n");
+ return inst_coms_fail;
+
+ got_coms:;
/* Check the response */
if (buf[0] != 0x7e || buf[1] != 0x20 || buf[2] != 0x02 || buf[3] != 0x00) {
@@ -609,6 +613,7 @@ inst_code smcube_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
smcube *p = (smcube *)pp;
@@ -621,6 +626,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *id = inst_calc_id_none;
id[0] = '\000';
if ((ev = smcube_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -1056,8 +1062,7 @@ static void set_optcalibs_default(smcube *p) {
* error if it hasn't been initialised.
*/
static inst_code
-smcube_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+smcube_get_set_opt(inst *pp, inst_opt_type m, ...) {
smcube *p = (smcube *)pp;
inst_code ev = inst_ok;
@@ -1114,13 +1119,17 @@ smcube_get_set_opt(inst *pp, inst_opt_type m, ...)
return inst_ok;
}
- /* Get/Sets that require instrument coms. */
- if (!p->gotcoms)
- return inst_no_coms;
- if (!p->inited)
- return inst_no_init;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
- return inst_unsupported;
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/smcube.h b/spectro/smcube.h
index 7283635..06aee9d 100644
--- a/spectro/smcube.h
+++ b/spectro/smcube.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define SMCUBE_INTERNAL_ERROR 0xff01 /* Internal software error */
#define SMCUBE_TIMEOUT 0xff02 /* Communication timeout */
@@ -67,7 +71,7 @@
struct _smcube {
INST_OBJ_BASE
- int bt; /* Bluetooth coms rather than USB/serial */
+ int bt; /* Bluetooth coms rather than USB/serial flag */
amutex lock; /* Command lock */
@@ -114,6 +118,9 @@ struct _smcube {
/* Constructor */
extern smcube *new_smcube(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define SMCUBE_H
#endif /* SMCUBE_H */
diff --git a/spectro/spec2cie.c b/spectro/spec2cie.c
index 322ab05..d77c334 100644
--- a/spectro/spec2cie.c
+++ b/spectro/spec2cie.c
@@ -1,7 +1,7 @@
/*
* Argyll Color Correction System
- * Spectral .ti3 file converter
+ * Spectral .ti3 or .sp file converter
*
* Copyright 2005 Gerhard Fuernkranz
* All rights reserved.
@@ -26,17 +26,17 @@
* under the GNU GENERAL PUBLIC LICENSE Version 3 :-
* see the License.txt file for licencing details.
*
- * This program takes the spectral data in a .ti3 file, converts them
+ * This program takes the spectral data in a .ti3 or .sp file, converts them
* to XYZ and Lab and fills the XYZ_[XYZ] and LAB_[LAB] columns in the
- * output .ti3 file with the computed XYZ and Lab values. If the columns
+ * output .ti3 or .sp file with the computed XYZ and Lab values. If the columns
* XYZ_[XYZ] and/or LAB_[LAB] are missing in the input file, they are
* added to the output file.
*
- * All other colums are copied from the input to the output .ti3 file.
+ * All other colums are copied from the input to the output .ti3 or .sp file.
*
* If the -f option is used, the FWA corrected spectral reflectances
- * are written to the output .ti3 file, instead of simply copying the
- * spectral reflectances from the input .ti3 file. In this case, the
+ * are written to the output .ti3 or .sp file, instead of simply copying the
+ * spectral reflectances from the input .ti3 or .sp file. In this case, the
* XYZ_[XYZ] and D50 LAB_[LAB] values are computed from the FWA corrected
* reflectances as well.
*/
@@ -50,10 +50,11 @@
Calibration tables aren't being passed through either ??
- L*a*b* is always D50.
-
This is intended for conversion of reflective measurements to XYZ -
there is no illuminant for emissive values.
+
+ L*a*b* is always D50.
+
*/
#define ALLOW_PLOT
@@ -74,33 +75,33 @@
#include "inst.h"
#ifdef ALLOW_PLOT
#include "plot.h"
-#endif
#include "ui.h"
+#endif
void
usage (void)
{
- fprintf (stderr, "Convert spectral .ti3 file, Version %s\n", ARGYLL_VERSION_STR);
+ fprintf (stderr, "Convert spectral .ti3 or .sp file, Version %s\n", ARGYLL_VERSION_STR);
fprintf (stderr, "Author: Gerhard Fuernkranz, licensed under the AGPL Version 3\n");
fprintf (stderr, "\n");
- fprintf (stderr, "Usage: spec2cie [options] input.ti3 output.ti3\n");
- fprintf (stderr, " -v Verbose mode\n");
- fprintf (stderr, " -I illum Override actual instrument illuminant in .ti3 file:\n");
- fprintf (stderr, " A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
- fprintf (stderr, " (only used in conjunction with -f)\n");
- fprintf (stderr, " -f [illum] Use Fluorescent Whitening Agent compensation [simulated inst. illum.:\n");
- fprintf (stderr, " M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n");
- fprintf (stderr, " -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n");
- fprintf (stderr, " A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
- fprintf (stderr, " -o observ Choose CIE Observer for spectral data:\n");
- fprintf (stderr, " 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2 or file.cmf\n");
- fprintf (stderr, " -n Don't output spectral values\n");
+ fprintf (stderr, "Usage: spec2cie [options] input.[ti3|sp] output.[ti3|sp]\n");
+ fprintf (stderr, " -v Verbose mode\n");
+ fprintf (stderr, " -I illum Override actual instrument illuminant in .ti3 or .sp file:\n");
+ fprintf (stderr, " A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf (stderr, " (only used in conjunction with -f)\n");
+ fprintf (stderr, " -f [illum] Use Fluorescent Whitening Agent compensation [simulated inst. illum.:\n");
+ fprintf (stderr, " M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n");
+ fprintf (stderr, " -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n");
+ fprintf (stderr, " A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf (stderr, " -o observ Choose CIE Observer for spectral data:\n");
+ fprintf (stderr, " 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2 or file.cmf\n");
+ fprintf (stderr, " -n Don't output spectral values\n");
#ifdef ALLOW_PLOT
- fprintf (stderr, " -p Plot each values spectrum\n");
+ fprintf (stderr, " -p Plot each values spectrum\n");
#endif
- fprintf (stderr, " input.ti3 Measurement file\n");
- fprintf (stderr, " output.ti3 Converted measurement file\n");
+ fprintf (stderr, " input.[ti3|sp] Measurement file\n");
+ fprintf (stderr, " output.[ti3|sp] Converted measurement file\n");
exit (1);
}
@@ -116,6 +117,7 @@ main(int argc, char *argv[])
cgats *ocg; /* output cgats structure */
cgats_set_elem *elems;
+ int isspect = 0; /* nz if SPECT file rathe than TI3 */
int isemis = 0; /* nz if this is an emissive reference */
int isdisp = 0; /* nz if this is a display device */
int isdnormed = 0; /* Has display data been normalised to 100 ? */
@@ -126,12 +128,18 @@ main(int argc, char *argv[])
int fwacomp = 0; /* FWA compensation */
int doplot = 0; /* Plot each patches spectrum */
char* illum_str = "D50";
- icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant, if set. */
xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */
- icxIllumeType illum = icxIT_none; /* Spectral defaults */
- xspect cust_illum; /* Custom CIE illumination spectrum */
- icxIllumeType inst_illum = icxIT_none; /* Spectral defaults */
+ /* if tillum == icxIT_custom */
+ icxIllumeType illum = icxIT_none; /* CIE calc. illuminant spectrum, and FWA inst. */
+ /* illuminant if tillum not set. */
+ xspect cust_illum; /* Custom CIE illumination spectrum if illum == icxIT_custom */
+ double *ill_wp = NULL; /* If illum is not D50, illum white point XYZ */
+ double _ill_wp[3]; /* (What ill_wp points at if it is not NULL) */
+ icxIllumeType inst_illum = icxIT_none; /* Actual instrument illumination */
xspect inst_cust_illum; /* Custom actual instrument illumination spectrum */
+ /* if inst_illum == icxIT_custom */
+
icxObserverType observ = icxOT_none;
xspect cust_observ[3]; /* Custom observer CMF's */
@@ -211,9 +219,18 @@ main(int argc, char *argv[])
inst_illum = icxIT_F10;
}
else { /* Assume it's a filename */
+ inst_meas_type mt;
+
inst_illum = icxIT_custom;
- if (read_xspect (&inst_cust_illum, na) != 0)
+ if (read_xspect (&inst_cust_illum, &mt,na) != 0)
usage ();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Instrument illuminant '%s' is wrong measurement type",na);
}
}
@@ -243,14 +260,24 @@ main(int argc, char *argv[])
} else if (strcmp(na, "F10") == 0) {
tillum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
tillum = icxIT_custom;
- if (read_xspect(&cust_tillum, na) != 0)
+ if (read_xspect(&cust_tillum, &mt, na) != 0)
usage();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Target illuminant '%s' is wrong measurement type",na);
}
}
}
/* CIE tristimulous spectral Illuminant type */
+ /* (and FWA simulated instrument illuminant if tillum == icxIT_none) */
else if (argv[fa][1] == 'i') {
fa = nfa;
if (na == NULL)
@@ -281,9 +308,18 @@ main(int argc, char *argv[])
illum = icxIT_F10;
}
else { /* Assume it's a filename */
+ inst_meas_type mt;
+
illum = icxIT_custom;
- if (read_xspect (&cust_illum, na) != 0)
+ if (read_xspect (&cust_illum, &mt, na) != 0)
usage ();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("CIE illuminant '%s' is wrong measurement type",na);
}
}
@@ -334,23 +370,32 @@ main(int argc, char *argv[])
/* Open and look at the .ti3 profile patches file */
- icg = new_cgats (); /* Create a CGATS structure */
+ icg = new_cgats (); /* Create a CGATS structure */
icg->add_other (icg, "CTI3"); /* Calibration Target Information 3 */
+ icg->add_other (icg, "SPECT"); /* Spectral file */
- ocg = new_cgats (); /* Create a CGATS structure */
+ ocg = new_cgats (); /* Create a CGATS structure */
ocg->add_other (ocg, "CTI3"); /* Calibration Target Information 3 */
+ icg->add_other (ocg, "SPECT"); /* Spectral file */
if (icg->read_name (icg, in_ti3_name))
error ("CGATS file read error: %s", icg->err);
- if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
- error ("Input file isn't a CTI3 format file");
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other
+ || (icg->t[0].oi != 0 && icg->t[0].oi != 1))
+ error ("Input file isn't a CTI3 or SPECT format file");
+
+ if (icg->t[0].oi == 1)
+ isspect = 1;
+
if (icg->ntables < 1)
error ("Input file doesn't contain at least one table");
/* add table to output file */
-
- ocg->add_table(ocg, tt_other, 0);
+ if (isspect)
+ ocg->add_table(ocg, tt_other, 1);
+ else
+ ocg->add_table(ocg, tt_other, 0);
/* copy keywords */
@@ -370,19 +415,39 @@ main(int argc, char *argv[])
}
}
- if ((dti = icg->find_kword (icg, 0, "DEVICE_CLASS")) < 0)
- error ("Input file doesn't contain keyword DEVICE_CLASS");
-
- /* Reflective options when not a reflective profile type */
- if (strcmp(icg->t[0].kdata[dti],"DISPLAY") == 0
- || strcmp(icg->t[0].kdata[dti],"EMISINPUT") == 0) {
- isemis = 1;
- if (illum != icxIT_none)
- error("-i illuminant can't be used for emissive reference type");
- if (fwacomp)
- error("-f FWA compensation can't be used for emissive reference type");
- fwacomp = 0;
- tillum = icxIT_none;
+ if (isspect) {
+ if ((dti = icg->find_kword (icg, 0, "MEAS_TYPE")) < 0)
+ error ("Input file doesn't contain keyword MEAS_TYPE");
+
+ /* Reflective options when not a reflective profile type */
+ if (strcmp(icg->t[0].kdata[dti],"EMISSION") == 0
+ || strcmp(icg->t[0].kdata[dti],"AMBIENT") == 0
+ || strcmp(icg->t[0].kdata[dti],"EMISSION_FLASH") == 0
+ || strcmp(icg->t[0].kdata[dti],"AMBIENT_FLASH") == 0) {
+ isemis = 1;
+ if (illum != icxIT_none)
+ error("-i illuminant can't be used for emissive reference type");
+ if (fwacomp)
+ error("-f FWA compensation can't be used for emissive reference type");
+ fwacomp = 0;
+ tillum = icxIT_none;
+ }
+
+ } else {
+ if ((dti = icg->find_kword (icg, 0, "DEVICE_CLASS")) < 0)
+ error ("Input file doesn't contain keyword DEVICE_CLASS");
+
+ /* Reflective options when not a reflective profile type */
+ if (strcmp(icg->t[0].kdata[dti],"DISPLAY") == 0
+ || strcmp(icg->t[0].kdata[dti],"EMISINPUT") == 0) {
+ isemis = 1;
+ if (illum != icxIT_none)
+ error("-i illuminant can't be used for emissive reference type");
+ if (fwacomp)
+ error("-f FWA compensation can't be used for emissive reference type");
+ fwacomp = 0;
+ tillum = icxIT_none;
+ }
}
/* Set defaults */
@@ -392,26 +457,30 @@ main(int argc, char *argv[])
if (observ == icxOT_none)
observ = icxOT_CIE_1931_2;
- /* Figure out what sort of device it is */
+ /* See if the display CIE data has been normalised to Y = 100 */
{
int ti;
- char *tos;
-
- if (strcmp (icg->t[0].kdata[dti], "DISPLAY") == 0) {
- isdisp = 1;
- }
- /* See if the display CIE data has been normalised to Y = 100 */
if ((ti = icg->find_kword(icg, 0, "NORMALIZED_TO_Y_100")) < 0
|| strcmp(icg->t[0].kdata[ti],"NO") == 0) {
isdnormed = 0;
} else {
isdnormed = 1;
}
+ }
+
+ /* Figure out what sort of device it is */
+ if (icg->find_kword(icg, 0, "COLOR_REP") >= 0) {
+ int ti;
+ char *tos;
if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
error("Input file doesn't contain keyword COLOR_REP");
+ if (strcmp (icg->t[0].kdata[dti], "DISPLAY") == 0) {
+ isdisp = 1;
+ }
+
if ((tos = strchr(icg->t[0].kdata[ti], '_')) == NULL)
tos = icg->t[0].kdata[ti];
@@ -513,7 +582,7 @@ main(int argc, char *argv[])
/* Read in the CGATs fields */
{
- int sidx; /* Sample ID index */
+// int sidx; /* Sample ID index */
int ti, ii;
int Xi, Yi, Zi, Li, ai, bi; /* CGATS indexes for each field */
int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
@@ -528,10 +597,12 @@ main(int argc, char *argv[])
xspect mwsp; /* FWA compensated medium white spectrum */
double mwXYZ[3]; /* Media white XYZ */
+#ifdef NEVER
if ((sidx = icg->find_field (icg, 0, "SAMPLE_ID")) < 0)
error ("Input file doesn't contain field SAMPLE_ID");
if (icg->t[0].ftype[sidx] != nqcs_t)
error ("Field SAMPLE_ID is wrong type");
+#endif
/* Using spectral data */
@@ -628,14 +699,28 @@ main(int argc, char *argv[])
error("Out of memory");
}
+ /* If CIE calculation illuminant is not standard, compute it's white point */
+ if (illum != icxIT_D50) {
+ ill_wp = _ill_wp;
+
+ /* Compute XYZ of illuminant */
+ if (icx_ill_sp2XYZ(ill_wp, observ, cust_observ, illum, 0.0, &cust_illum) != 0)
+ error("icx_ill_sp2XYZ returned error");
+ }
+
/* Create a spectral conversion object */
- if ((sp2cie = new_xsp2cie (illum,
- illum == icxIT_none ? NULL : &cust_illum,
- observ, cust_observ, icSigXYZData, icxClamp)) == NULL)
+ if ((sp2cie = new_xsp2cie(illum, &cust_illum, observ, cust_observ,
+ icSigXYZData, icxClamp)) == NULL)
{
error ("Creation of spectral conversion object failed");
}
+ if (fwacomp && devspace == icmSigDefaultData) {
+ // In theory could fake white spectra by accumulating max of
+ // all values as an alternative.
+ error ("No device values, so can't locate white patch for FWA compensation");
+ }
+
if (fwacomp) {
double nw = 0.0; /* Number of media white patches */
@@ -741,6 +826,8 @@ main(int argc, char *argv[])
}
}
+ /* Enable FWA, and use tillump as instrument illuminant if */
+ /* it is set, else use observer illuminant set by new_xsp2cie(). */
/* (Note that sp and mwsp.norm is set to 100.0) */
if (sp2cie->set_fwa(sp2cie, &insp, tillump, &mwsp))
error ("Set FWA on sp2cie failed");
@@ -755,6 +842,15 @@ main(int argc, char *argv[])
sp2cie->sconvert (sp2cie, &rmwsp, mwXYZ, &mwsp);
}
+ /* If CIE conversion illuminant is non-standard, add it to the output */
+ if (ill_wp != NULL) {
+ char buf[100];
+
+ sprintf(buf,"%f %f %f", ill_wp[0], ill_wp[1], ill_wp[2]);
+ ocg->add_kword(ocg, 0, "ILLUMINANT_WHITE_POINT_XYZ",buf, NULL);
+ }
+
+ /* Transform patches from spectral to CIE */
for (i = 0; i < npat; i++) {
xspect corr_sp;
diff --git a/spectro/specbos.c b/spectro/specbos.c
index 491fe97..4c5e4ba 100644
--- a/spectro/specbos.c
+++ b/spectro/specbos.c
@@ -2,7 +2,7 @@
/*
* Argyll Color Correction System
*
- * JETI specbos 1211/1201 related functions
+ * JETI specbos & spectraval related functions
*
* Author: Graeme W. Gill
* Date: 13/3/2013
@@ -38,9 +38,15 @@
TTBD:
- Should add a reflective and transmissive modes,
+ Should add a reflective mode,
by doing a white calibration and dividing the measurement.
+ Should check transmissive white spectral quality
+
+ Should save transmissive white cal. into file, and restore it on startup.
+
+ Should time transmissive white cal out.
+
*/
#include <stdio.h>
@@ -78,6 +84,14 @@ static int icoms2specbos_err(int se) {
return SPECBOS_OK;
}
+/* Type of reply terminator expected */
+typedef enum {
+ tnorm = 0, /* Normal terminators */
+ tmeas = 1, /* Measurement command */
+ trefr = 2, /* Refresh measurement */
+ tspec = 3 /* Spectraval spectral read */
+} spterm;
+
/* Do a full command/response echange with the specbos */
/* (This level is not multi-thread safe) */
/* Return the specbos error code. */
@@ -89,26 +103,28 @@ char *out, /* Out string buffer */
int bsize, /* Out buffer size */
double to, /* Timeout in seconds */
int ntc, /* Number or termination chars */
-int ctype, /* 0 = normal, 1 = *init, 2 = refr reading */
+spterm ctype, /* Exected reply terminator type */
int nd /* nz to disable debug messages */
) {
int se;
int bread = 0;
char *cp, *tc = "", *dp;
- if (ctype == 0)
+ if (ctype == tnorm)
tc = "\r\006\025"; /* Return, Ack or Nak */
- else if (ctype == 1)
+ else if (ctype == tmeas)
tc = "\007\025"; /* Bell or Nak */
- else if (ctype == 2)
+ else if (ctype == trefr)
tc = "\r\025"; /* Return or Nak */
+ else if (ctype == tspec)
+ tc = "\003\025"; /* Atx or Nak */
- se = p->icom->write_read(p->icom, in, 0, out, bsize, &bread, tc, ntc, to);
+ se = p->icom->write_read_ex(p->icom, in, 0, out, bsize, &bread, tc, ntc, to, 1);
/* Because we are sometimes waiting for 3 x \r characters to terminate the read, */
- /* we will instead time out on getting a single NAK (\025), so convert timout */
- /* with bytes to non-timeout, so that we can process the error. */
- if (se == ICOM_TO && bread > 0)
+ /* we will instead time out on getting a single NAK (\025), so ignore timout */
+ /* if we got a NAK. */
+ if (se == ICOM_TO && bread > 0 && out[0] == '\025')
se = ICOM_OK;
if (se != 0) {
@@ -116,6 +132,14 @@ int nd /* nz to disable debug messages */
return icoms2specbos_err(se);
}
+ /* Over Bluetooth, we get an erronious string "AT+JSCR\r\n" mixed in our output. */
+ /* This would appear to be from the eBMU Bluetooth adapter AT command set. */
+ if (bread > 9 && strncmp(out, "AT+JSCR\r\n", 9) == 0) {
+ a1logd(p->log, 8, "specbos: ignored 'AT+JSCR\\r\\n' response\n");
+ memmove(out, out+9, bsize-9);
+ bread -= 9;
+ }
+
/* See if there was an error, and remove any enquire codes */
for (dp = cp = out; *cp != '\000' && (dp - out) < bsize; cp++) {
if (*cp == '\025') { /* Got a NAK */
@@ -125,9 +149,16 @@ int nd /* nz to disable debug messages */
if (!nd) a1logd(p->log, 1, "specbos_fcommand: serial i/o failure on write_read '%s'\n",icoms_fix(in));
return icoms2specbos_err(se);;
}
- if (sscanf(buf, "Error Code: %d ",&se) != 1) {
- if (!nd) a1logd(p->log, 1, "specbos_fcommand: failed to parse error code '%s'\n",icoms_fix(buf));
- return SPECBOS_DATA_PARSE_ERROR;
+ if (p->model == 1501 || p->model == 1511) {
+ if (sscanf(buf, "%d ",&se) != 1) {
+ if (!nd) a1logd(p->log, 1, "specbos_fcommand: failed to parse error code '%s'\n",icoms_fix(buf));
+ return SPECBOS_DATA_PARSE_ERROR;
+ }
+ } else {
+ if (sscanf(buf, "Error Code: %d ",&se) != 1) {
+ if (!nd) a1logd(p->log, 1, "specbos_fcommand: failed to parse error code '%s'\n",icoms_fix(buf));
+ return SPECBOS_DATA_PARSE_ERROR;
+ }
}
if (!nd) a1logd(p->log, 1, "Got specbos error code %d\n",se);
@@ -155,7 +186,7 @@ char *in, /* In string */
char *out, /* Out string buffer */
int bsize, /* Out buffer size */
double to) { /* Timout in seconds */
- int rv = specbos_fcommand(p, in, out, bsize, to, 1, 0, 0);
+ int rv = specbos_fcommand(p, in, out, bsize, to, 1, tnorm, 0);
return specbos_interp_code((inst *)p, rv);
}
@@ -186,8 +217,10 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
specbos *p = (specbos *) pp;
char buf[MAX_MES_SIZE];
baud_rate brt[] = { baud_921600, baud_115200, baud_38400, baud_nc };
+// spectraval 38400, 115200, 230400, 921600, 3000000
+
unsigned int etime;
- unsigned int i;
+ unsigned int len, i;
instType itype = pp->itype;
int se;
@@ -195,64 +228,104 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
a1logd(p->log, 2, "specbos_init_coms: About to init Serial I/O\n");
- amutex_lock(p->lock);
- if (p->icom->port_type(p->icom) != icomt_serial
- && p->icom->port_type(p->icom) != icomt_usbserial) {
- amutex_unlock(p->lock);
- a1logd(p->log, 1, "specbos_init_coms: wrong communications type for device!\n");
+ if (!(p->icom->dctype & icomt_serial)
+ && !(p->icom->dctype & icomt_fastserial)) {
+ a1logd(p->log, 1, "specbos_init_coms: wrong communications type for device! (dctype 0x%x)\n",p->icom->dctype);
return inst_coms_fail;
}
- /* The tick to give up on */
- etime = msec_time() + (long)(1500.0 + 0.5);
+ /* Communications has already been established over BlueTooth serial */
+ if (p->bt) {
- a1logd(p->log, 1, "specbos_init_coms: Trying different baud rates (%u msec to go)\n",etime - msec_time());
+ amutex_lock(p->lock);
- /* Until we time out, find the correct baud rate */
- for (i = 0; msec_time() < etime; i++) {
- if (brt[i] == baud_nc) {
- i = 0;
- }
- a1logd(p->log, 5, "specbos_init_coms: trying baud ix %d\n",brt[i]);
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
- stop_1, length_8)) != ICOM_OK) {
+ /* Let instrument get its act together */
+ msec_sleep(600);
+
+ /* Get the instrument identification */
+ if ((ev = specbos_command(p, "*idn?\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok) {
amutex_unlock(p->lock);
- a1logd(p->log, 5, "specbos_init_coms: set_ser_port failed with 0x%x\n",se);
- return specbos_interp_code((inst *)p, icoms2specbos_err(se));; /* Give up */
+ a1logd(p->log, 2, "specbos_init_coms: idn didn't return\n");
+ return ev;
}
+ /* We need to setup communications */
+ } else {
+ int delayms = 0;
+ amutex_lock(p->lock);
- /* Check instrument is responding */
- if (((ev = specbos_command(p, "*idn?\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
- != inst_coms_fail) {
- break; /* We've got coms or user abort */
- }
+ /* The tick to give up on */
+ etime = msec_time() + (long)(1500.0 + 0.5);
- /* Check for user abort */
- if (p->uicallback != NULL) {
- inst_code ev;
- if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "specbos_init_coms: Trying different baud rates (%u msec to go)\n",etime - msec_time());
+
+ /* Spectraval Bluetooth serial doesn't seem to actuall function */
+ /* until 600msec after it is opened. We get arroneos "AT+JSCR\r\n" reply */
+ /* within that time, and it won't re-open after closing. */
+ if (p->icom->dctype & icomt_btserial)
+ delayms = 600;
+
+ /* Until we time out, find the correct baud rate */
+ for (i = 0; msec_time() < etime; i++) {
+ if (brt[i] == baud_nc) {
+ i = 0;
+ }
+
+ /* Only connect at 115200 if bluetooth */
+ if ((p->icom->dctype & icomt_btserial) != 0 && brt[i] != baud_115200)
+ continue;
+
+ a1logd(p->log, 5, "specbos_init_coms: Trying %s baud, %d msec to go\n",
+ baud_rate_to_str(brt[i]), etime- msec_time());
+ if ((se = p->icom->set_ser_port_ex(p->icom, fc_None, brt[i], parity_none,
+ stop_1, length_8, delayms)) != ICOM_OK) {
amutex_unlock(p->lock);
- a1logd(p->log, 1, "specbos_init_coms: user aborted\n");
- return inst_user_abort;
+ a1logd(p->log, 5, "specbos_init_coms: set_ser_port failed with 0x%x\n",se);
+ return specbos_interp_code((inst *)p, icoms2specbos_err(se));; /* Give up */
+ }
+
+// if ((p->icom->sattr & icom_bt) != 0)
+// specbos_command(p, "\r", buf, MAX_MES_SIZE, 0.5);
+
+ /* Check instrument is responding */
+ if (((ev = specbos_command(p, "*idn?\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail) {
+ goto got_coms; /* We've got coms or user abort */
+ }
+
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ amutex_unlock(p->lock);
+ a1logd(p->log, 1, "specbos_init_coms: user aborted\n");
+ return inst_user_abort;
+ }
}
}
- }
- if (msec_time() >= etime) { /* We haven't established comms */
+ /* We haven't established comms */
amutex_unlock(p->lock);
a1logd(p->log, 2, "specbos_init_coms: failed to establish coms\n");
return inst_coms_fail;
+
+ got_coms:;
}
/* Check the response */
+ len = strlen(buf);
p->model = 0;
- if (strncmp (buf, "SB05", 4) == 0) /* Special case */
+ if (len >= 4 && strncmp(buf, "SB05", 4) == 0) {
p->model = 1201;
- else {
- if (strlen(buf) < 11
+ } else if ((len >= 10 && strncmp(buf, "JETI_SDCM3", 10) == 0)
+ || (len >= 9 && strncmp(buf, "DCM3_JETI", 9) == 0)
+ || (len >= 17 && strncmp(buf, "PECFIRM_JETI_1501", 18) == 0)
+ || (len >= 18 && strncmp(buf, "SPECFIRM_JETI_1501", 17) == 0)) {
+ p->model = 1501;
+ } else {
+ if (len < 11
|| sscanf(buf, "JETI_SB%d\r", &p->model) != 1) {
amutex_unlock(p->lock);
a1logd(p->log, 2, "specbos_init_coms: unrecognised ident string '%s'\n",icoms_fix(buf));
@@ -260,7 +333,9 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
}
}
- if (p->model != 1201 && p->model != 1211) {
+ if (p->model != 1201
+ && p->model != 1211
+ && p->model != 1501) {
amutex_unlock(p->lock);
a1logd(p->log, 2, "specbos_init_coms: unrecognised model %04d\n",p->model);
return inst_unknown_model;
@@ -269,6 +344,40 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
p->gotcoms = 1;
+ /* See if it's a 1501 or 1511 */
+ if (p->model == 1501) {
+ int dispen = 0;
+
+ if ((ev = specbos_command(p, "*conf:dispen?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ a1logd(p->log, 2, "specbos_init_coms: failed to get display status\n");
+ return inst_protocol_error;
+ }
+ if (sscanf(buf, "%d ",&dispen) != 1) {
+ amutex_unlock(p->lock);
+ a1loge(p->log, 1, "specbos_init_inst: failed to parse display status\n");
+ return ev;
+ }
+ a1logd(p->log, 1, " spectraval %s display\n",dispen ? "has" : "doesn't have");
+ if (dispen) {
+ p->model = 1511;
+
+ /* Set remote mode */
+ if ((ev = specbos_command(p, "*REMOTE 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ a1logd(p->log, 2, "specbos_init_coms: failed to set remote mode\n");
+ return inst_protocol_error;
+ }
+ }
+
+ /* Check Bluetooth status */
+ if ((ev = specbos_command(p, "*conf:bten?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ a1logd(p->log, 2, "specbos_init_coms: failed to get Bluetooth status\n");
+ return inst_protocol_error;
+ }
+ }
+
#ifdef NEVER /* Test a change in baud rate on next plug in */
a1logd(p->log, 2, "specbos_init_coms: changing baudrate\n");
// if ((ev = specbos_command(p, "*para:baud 384\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok)
@@ -285,12 +394,11 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
#endif
amutex_unlock(p->lock);
-
return inst_ok;
}
/*
- Notes on commands
+ Notes on commands for 1201:
*conf is temporary, *para can be saved to instrument
Since we set the instrument up every time, use *conf ?
@@ -378,7 +486,8 @@ int specbos_diff_thread(void *pp) {
int pos;
amutex_lock(p->lock);
- rv1 = specbos_get_diffpos(p, &pos, 1);
+ if (p->model != 1501 && p->model != 1511)
+ rv1 = specbos_get_diffpos(p, &pos, 1);
rv2 = specbos_get_target_laser(p, &p->laser, 1);
amutex_unlock(p->lock);
@@ -419,9 +528,11 @@ specbos_init_inst(inst *pp) {
amutex_lock(p->lock);
- /* Restore the instrument to it's default settings */
- if ((ev = specbos_command(p, "*conf:default\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok)
- return ev;
+ if (p->model != 1501 && p->model != 1511) {
+ /* Restore the instrument to it's default settings */
+ if ((ev = specbos_command(p, "*conf:default\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok)
+ return ev;
+ }
/* Set calibration type to auto on ambient cap */
if ((ev = specbos_command(p, "*para:calibn 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
@@ -429,78 +540,177 @@ specbos_init_inst(inst *pp) {
return ev;
}
- /* Set auto exposure/integration time */
- /* Set calibration type to auto on ambient cap */
- if ((ev = specbos_command(p, "*para:expo 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok
- || (ev = specbos_command(p, "*para:adapt 2\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
+ if (p->model == 1501 || p->model == 1511) {
+ /* Set auto exposure/integration time */
+ if ((ev = specbos_command(p, "*para:tint 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+ } else {
+ /* Set auto exposure/integration time */
+ if ((ev = specbos_command(p, "*para:expo 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok
+// || (ev = specbos_command(p, "*para:adapt 2\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok
+ ) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
}
- p->measto = 20.0; /* default */
+ p->measto = 20.0; /* Set default. Specbos default is 60.0 */
if (p->model == 1211)
- p->measto = 5.0; /* Same overall time as i1d3 ?? */
+ p->measto = 6.0; /* Same overall time as i1d3 ?? */
else if (p->model == 1201)
- p->measto = 15.0;
+ p->measto = 16.0;
+ else if (p->model == 1501 || p->model == 1511)
+ p->measto = 6.0;
- /* Set maximum integration time to speed up display measurement */
- sprintf(mes, "*conf:maxtin %d\r", (int)(p->measto * 1000.0+0.5));
- if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
- }
+ /* Implement max auto int. time, to speed up display measurement */
+ if (p->model == 1501 || p->model == 1511) {
+ int maxaver = 2; /* Maximum averages for auto int time */
+ double dmaxtint;
+ int maxtint;
- /* Set the measurement function to be Radiometric spectrum */
- if ((ev = specbos_command(p, "*conf:func 6\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
- }
+ /* Actual time taken depends on maxtint, autoavc & fudge factor. */
+ dmaxtint = p->measto/(maxaver + 3.5);
- /* Set the measurement format to ASCII */
- if ((ev = specbos_command(p, "*conf:form 4\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
- }
+ maxtint = (int)(dmaxtint * 1000.0+0.5);
- if ((ev = specbos_command(p, "*para:wavbeg?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
- }
- if (sscanf(buf, "Predefined start wave: %lf ",&p->wl_short) != 1) {
- amutex_unlock(p->lock);
- a1loge(p->log, 1, "specbos_init_inst: failed to parse start wave\n");
- return ev;
- }
- a1logd(p->log, 1, " Short wl range %f\n",p->wl_short);
+ if (maxtint < 1000 || maxtint > 64999)
+ error("specbos: assert, maxtint %d out of range",maxtint);
- if ((ev = specbos_command(p, "*para:wavend?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
- }
- if (sscanf(buf, "Predefined end wave: %lf ",&p->wl_long) != 1) {
- amutex_unlock(p->lock);
- a1loge(p->log, 1, "specbos_init_inst: failed to parse end wave\n");
- return ev;
- }
- if (p->wl_long > 830.0) /* Could go to 1000 with 1211 */
- p->wl_long = 830.0; /* Limit it to useful visual range */
+ /* Set maximum integration time */
+ sprintf(mes, "*para:maxtint %d\r", maxtint);
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
- a1logd(p->log, 1, " Long wl range %f\n",p->wl_long);
+ /* Set maximum number of auto averages. Min value is 2 */
+ sprintf(mes, "*para:maxaver %d\r", maxaver);
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
- p->nbands = (int)((p->wl_long - p->wl_short + 1.0)/1.0 + 0.5);
+ /* spectraval doesn't support *fetch:XYZ command */
+ p->noXYZ = 1;
- /* Set the wavelength range and resolution */
- sprintf(mes, "*conf:wran %d %d 1\r", (int)(p->wl_short+0.5), (int)(p->wl_long+0.5));
- if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
+ } else {
+ double dmaxtin;
+ int maxtin;
+
+ dmaxtin = p->measto/2.5; /* Fudge factor */
+ maxtin = (int)(dmaxtin * 1000.0+0.5);
+
+ if (maxtin < 1000 || maxtin > 64999)
+ error("specbos: assert, maxtin %d out of range",maxtin);
+
+ /* Set maximum integration time */
+ sprintf(mes, "*para:maxtint %d\r", maxtin);
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
}
- /* Set to average just 1 reading */
- if ((ev = specbos_command(p, "*conf:aver 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
+ if (p->model == 1501 || p->model == 1511) {
+ int wstart, wend, wstep;
+
+ /* Set the measurement format to None. We will read measurement manually. */
+ /* (0 = None, 1 = Binary, 2 = ASCII) */
+ if ((ev = specbos_command(p, "*para:form 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+
+ if ((ev = specbos_command(p, "*para:wran?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+ if (sscanf(buf, "%d %d %d",&wstart,&wend,&wstep) != 3) {
+ amutex_unlock(p->lock);
+ a1loge(p->log, 1, "specbos_init_inst: failed to parse wavelength range\n");
+ return ev;
+ }
+
+ p->wl_short = (double)wstart;
+ p->wl_long = (double)wend;
+
+ a1logd(p->log, 1, " Short wl range %f\n",p->wl_short);
+
+ if (p->wl_long > 830.0)
+ p->wl_long = 830.0; /* Limit it to useful visual range */
+
+ a1logd(p->log, 1, " Long wl range %f\n",p->wl_long);
+
+ p->nbands = (int)((p->wl_long - p->wl_short + 1.0)/1.0 + 0.5);
+
+ /* Set the wavelength range and resolution */
+ sprintf(mes, "*para:wran %d %d 1\r", (int)(p->wl_short+0.5), (int)(p->wl_long+0.5));
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+
+ /* Set to average just 1 reading */
+ if ((ev = specbos_command(p, "*para:aver 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+ } else {
+
+ /* Set the measurement function to be Radiometric spectrum */
+ if ((ev = specbos_command(p, "*conf:func 6\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+
+ /* Set the measurement format to ASCII */
+ if ((ev = specbos_command(p, "*conf:form 4\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+
+ if ((ev = specbos_command(p, "*para:wavbeg?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+ if (sscanf(buf, "Predefined start wave: %lf ",&p->wl_short) != 1) {
+ amutex_unlock(p->lock);
+ a1loge(p->log, 1, "specbos_init_inst: failed to parse start wave\n");
+ return ev;
+ }
+ a1logd(p->log, 1, " Short wl range %f\n",p->wl_short);
+
+ if ((ev = specbos_command(p, "*para:wavend?\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+ if (sscanf(buf, "Predefined end wave: %lf ",&p->wl_long) != 1) {
+ amutex_unlock(p->lock);
+ a1loge(p->log, 1, "specbos_init_inst: failed to parse end wave\n");
+ return ev;
+ }
+ if (p->wl_long > 830.0) /* Could go to 1000 with 1211 */
+ p->wl_long = 830.0; /* Limit it to useful visual range */
+
+ a1logd(p->log, 1, " Long wl range %f\n",p->wl_long);
+
+ p->nbands = (int)((p->wl_long - p->wl_short + 1.0)/1.0 + 0.5);
+
+ /* Set the wavelength range and resolution */
+ sprintf(mes, "*conf:wran %d %d 1\r", (int)(p->wl_short+0.5), (int)(p->wl_long+0.5));
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+
+ /* Set to average just 1 reading */
+ if ((ev = specbos_command(p, "*conf:aver 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
}
if (p->log->verb) {
@@ -558,6 +768,7 @@ static inst_code specbos_imp_measure_set_refresh(specbos *p);
static inst_code specbos_imp_set_refresh(specbos *p);
/* Get the ambient diffuser position */
+/* (Not valid for 1501 or 1511) */
/* (This is not multithread safe) */
static inst_code
specbos_get_diffpos(
@@ -569,7 +780,7 @@ specbos_get_diffpos(
int ec;
/* See if we're in emissive or ambient mode */
- if ((ec = specbos_fcommand(p, "*contr:mhead?\r", buf, MAX_MES_SIZE, 1.0, 1, 0, nd)) != inst_ok) {
+ if ((ec = specbos_fcommand(p, "*contr:mhead?\r", buf, MAX_MES_SIZE, 1.0, 1, tnorm, nd)) != inst_ok) {
return specbos_interp_code((inst *)p, ec);
}
if (sscanf(buf, "mhead: %d ",pos) != 1) {
@@ -591,17 +802,61 @@ specbos_get_target_laser(
int ec;
int lstate;
- if ((ec = specbos_fcommand(p, "*contr:laser?\r", buf, MAX_MES_SIZE, 1.0, 1, 0, nd)) != inst_ok) {
+ if ((ec = specbos_fcommand(p, "*contr:laser?\r", buf, MAX_MES_SIZE, 1.0, 1, tnorm, nd)) != inst_ok) {
return specbos_interp_code((inst *)p, ec);
}
- if (sscanf(buf, "laser: %d ",&lstate) != 1) {
- a1loge(p->log, 2, "specbos_get_target_laser: failed to parse laser state\n");
- return inst_protocol_error;
+ if (p->model == 1501 || p->model == 1511) {
+ if (sscanf(buf, "%d ",&lstate) != 1) {
+ a1loge(p->log, 2, "specbos_get_target_laser: failed to parse laser state\n");
+ return inst_protocol_error;
+ }
+ } else {
+ if (sscanf(buf, "laser: %d ",&lstate) != 1) {
+ a1loge(p->log, 2, "specbos_get_target_laser: failed to parse laser state\n");
+ return inst_protocol_error;
+ }
}
*laser = lstate;
return inst_ok;
}
+/* Configure for averaging */
+static inst_code set_average(specbos *p, int nav, int lock) {
+ char mes[100];
+ char buf[MAX_MES_SIZE];
+ inst_code ev;
+
+ if (lock) amutex_lock(p->lock);
+
+ if (p->model == 1501 || p->model == 1511) {
+ /* Set number to average */
+ sprintf(mes, "*para:aver %d\r", nav);
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ if (lock) amutex_unlock(p->lock);
+ return ev;
+ }
+ } else {
+ /* Set number to average */
+ sprintf(mes, "*conf:aver %d\r", nav);
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ if (lock) amutex_unlock(p->lock);
+ return ev;
+ }
+ }
+
+#ifdef NEVER /* Doesn't seem to make any difference ? */
+ /* Only dark average at start of batch */
+ sprintf(mes, "*conf:darkm %d\r", nav == 1 ? 0 : 1);
+ if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ if (lock) amutex_unlock(p->lock);
+ return ev;
+ }
+#endif
+
+ if (lock) amutex_unlock(p->lock);
+ return inst_ok;
+}
+
/* Read a single sample */
/* Return the dtp error code */
static inst_code
@@ -622,9 +877,15 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if (!p->inited)
return inst_no_init;
+ /* Request calibration if it is needed */
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission
+ && p->trans_white.spec_n == 0) {
+ return inst_needs_cal;
+ }
+
amutex_lock(p->lock);
- if (p->trig == inst_opt_trig_user) {
+ if (!p->doing_cal && p->trig == inst_opt_trig_user) {
amutex_unlock(p->lock);
if (p->uicallback == NULL) {
@@ -650,7 +911,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
amutex_lock(p->lock);
/* Progromatic Trigger */
- } else {
+ } else if (!p->doing_cal) {
/* Check for abort */
if (p->uicallback != NULL
&& (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) {
@@ -659,21 +920,23 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
}
- /* See if we're in emissive or ambient mode */
- if ((rv = specbos_get_diffpos(p, &pos, 0) ) != inst_ok) {
- amutex_unlock(p->lock);
- return rv;
- }
-
- if (p->mode & inst_mode_ambient) {
- if (pos != 1) {
+ if (p->model != 1501 && p->model != 1511) {
+ /* See if we're in emissive or ambient mode */
+ if ((rv = specbos_get_diffpos(p, &pos, 0) ) != inst_ok) {
amutex_unlock(p->lock);
- return specbos_interp_code((inst *)p, SPECBOS_SPOS_AMB);
+ return rv;
}
- } else {
- if (pos != 0) {
- amutex_unlock(p->lock);
- return specbos_interp_code((inst *)p, SPECBOS_SPOS_EMIS);
+
+ if (p->mode & inst_mode_ambient) {
+ if (pos != 1) {
+ amutex_unlock(p->lock);
+ return specbos_interp_code((inst *)p, SPECBOS_SPOS_AMB);
+ }
+ } else {
+ if (pos != 0) {
+ amutex_unlock(p->lock);
+ return specbos_interp_code((inst *)p, SPECBOS_SPOS_EMIS);
+ }
}
}
@@ -693,9 +956,26 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
}
+ /* Set to average 10 readings for transmission */
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ if ((rv = set_average(p, 10, 0)) != inst_ok)
+ return rv;
+ }
+
+ if (p->model == 1501 || p->model == 1511) {
+ /* Set the measurement format to None. We will read measurement manually. */
+ if ((rv = specbos_command(p, "*para:form 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return rv;
+ }
+ }
+
/* Trigger a measurement */
/* (Note that ESC will abort it) */
- ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, 5.0 * p->measto + 10.0 , 1, 1, 0);
+ if (p->model == 1501 || p->model == 1511)
+ ec = specbos_fcommand(p, "*meas:refer\r", buf, MAX_MES_SIZE, p->measto + 10.0 , 1, tmeas, 0);
+ else
+ ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, p->measto + 10.0 , 1, tmeas, 0);
// Test out bug workaround
// if (!p->badCal) ec = SPECBOS_EXCEED_CAL_WL;
@@ -719,15 +999,24 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
/* Re-set the wavelength range and resolution */
sprintf(mes, "*conf:wran %d %d 1\r", (int)(p->wl_short+0.5), (int)(p->wl_long+0.5));
if ((ev = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission)
+ set_average(p, 1, 0);
amutex_unlock(p->lock);
return ev;
}
p->badCal = 1;
/* Try command again */
- ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, 5.0 * p->measto + 10.0 , 1, 1, 0);
+ if (p->model == 1501 || p->model == 1511)
+ ec = specbos_fcommand(p, "*meas:refer\r", buf, MAX_MES_SIZE, p->measto + 10.0 , 1, tmeas, 0);
+ else
+ ec = specbos_fcommand(p, "*init\r", buf, MAX_MES_SIZE, p->measto + 10.0 , 1, tmeas, 0);
}
+ /* Restore single reading if transmission */
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission)
+ set_average(p, 1, 0);
+
if (ec != SPECBOS_OK) {
amutex_unlock(p->lock);
return specbos_interp_code((inst *)p, ec);
@@ -738,7 +1027,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
ec = SPECBOS_COMMAND;
} else { /* Read the XYZ */
- ec = specbos_fcommand(p, "*fetch:XYZ\r", buf, MAX_RD_SIZE, 0.5, 3, 0, 0);
+ ec = specbos_fcommand(p, "*fetch:XYZ\r", buf, MAX_RD_SIZE, 0.5, 3, tnorm, 0);
}
@@ -758,26 +1047,52 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
p->noXYZ = 1;
- if ((ec = specbos_fcommand(p, "*fetch:PHOTOmetric\r", buf, MAX_RD_SIZE, 0.5, 3, 0, 0))
- != SPECBOS_OK) {
- amutex_unlock(p->lock);
- return specbos_interp_code((inst *)p, ec);
- }
- if (sscanf(buf, "Luminance[cd/m^2]: %lf ", &Yxy[0]) != 1) {
- amutex_unlock(p->lock);
- a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf);
- return inst_protocol_error;
+ if (p->model == 1501 || p->model == 1511) {
+ if ((ec = specbos_fcommand(p, "*calc:PHOTOmetric\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0))
+ != SPECBOS_OK) {
+ amutex_unlock(p->lock);
+ return specbos_interp_code((inst *)p, ec);
+ }
+ if (sscanf(buf, "%lf ", &Yxy[0]) != 1) {
+ amutex_unlock(p->lock);
+ a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf);
+ return inst_protocol_error;
+ }
+ } else {
+ if ((ec = specbos_fcommand(p, "*fetch:PHOTOmetric\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0))
+ != SPECBOS_OK) {
+ amutex_unlock(p->lock);
+ return specbos_interp_code((inst *)p, ec);
+ }
+ if (sscanf(buf, "Luminance[cd/m^2]: %lf ", &Yxy[0]) != 1) {
+ amutex_unlock(p->lock);
+ a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf);
+ return inst_protocol_error;
+ }
}
- if ((ec = specbos_fcommand(p, "*fetch:CHROMXY\r", buf, MAX_RD_SIZE, 0.5, 3, 0, 0))
- != SPECBOS_OK) {
- amutex_unlock(p->lock);
- return specbos_interp_code((inst *)p, ec);
- }
- if (sscanf(buf, "Chrom_x: %lf Chrom_y: %lf ", &Yxy[1], &Yxy[2]) != 2) {
- amutex_unlock(p->lock);
- a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf);
- return inst_protocol_error;
+ if (p->model == 1501 || p->model == 1511) {
+ if ((ec = specbos_fcommand(p, "*calc:CHROMXY\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0))
+ != SPECBOS_OK) {
+ amutex_unlock(p->lock);
+ return specbos_interp_code((inst *)p, ec);
+ }
+ if (sscanf(buf, " %lf %lf ", &Yxy[1], &Yxy[2]) != 2) {
+ amutex_unlock(p->lock);
+ a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf);
+ return inst_protocol_error;
+ }
+ } else {
+ if ((ec = specbos_fcommand(p, "*fetch:CHROMXY\r", buf, MAX_RD_SIZE, 0.5, 1, tnorm, 0))
+ != SPECBOS_OK) {
+ amutex_unlock(p->lock);
+ return specbos_interp_code((inst *)p, ec);
+ }
+ if (sscanf(buf, "Chrom_x: %lf Chrom_y: %lf ", &Yxy[1], &Yxy[2]) != 2) {
+ amutex_unlock(p->lock);
+ a1logd(p->log, 1, "specbos_read_sample: failed to parse '%s'\n",buf);
+ return inst_protocol_error;
+ }
}
icmYxy2XYZ(val->XYZ, Yxy);
@@ -790,9 +1105,10 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if (clamp)
icmClamp3(val->XYZ, val->XYZ);
val->loc[0] = '\000';
+ /* Ambient or Trans 90/diffuse */
if (p->mode & inst_mode_ambient) {
val->mtype = inst_mrt_ambient;
- } else
+ } else /* Emis or Trans diffuse/90 */
val->mtype = inst_mrt_emission;
val->XYZ_v = 1; /* These are absolute XYZ readings */
val->sp.spec_n = 0;
@@ -800,32 +1116,45 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
rv = inst_ok;
- /* spectrum data is returned only if requested */
- if (p->mode & inst_mode_spectral) {
+ /* spectrum data is returned only if requested, */
+ /* or if we are emulating transmission mode */
+ if (p->mode & inst_mode_spectral
+ || (p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
int tries, maxtries = 5;
- int i, xsize;
+ int ii,i, xsize;
char *cp, *ncp;
- /* (Format 12 doesn't seem to work on the 1211) */
- /* (Format 9 reportedly doesn't work on the 1201) */
- /* The folling works on the 1211 and is reported to work on the 1201 */
+ if (p->model == 1501 || p->model == 1511) {
+ /* Turn on spetrum output */
+ if ((ec = specbos_command(p, "*para:form 2\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ec;
+ }
+ ii = 0; /* Spectrum from the start */
+ } else {
+ ii = -2; /* Skip first two tokens */
+
+ /* (Format 12 doesn't seem to work on the 1211) */
+ /* (Format 9 reportedly doesn't work on the 1201) */
+ /* The folling works on the 1211 and is reported to work on the 1201 */
+ }
/* Because the specbos doesn't use flow control in its */
/* internal serial communications, it may overrun */
/* the FT232R buffer, so retry fetching the spectra if */
/* we get a comm error or parsing error. */
- for (tries = 0;;) {
+ for (tries = 0; tries < maxtries; tries++) {
/* Fetch the spectral readings */
- ec = specbos_fcommand(p, "*fetch:sprad\r", buf, MAX_RD_SIZE, 4.0, 2+p->nbands+1, 0, 0);
- tries++;
+ if (p->model == 1501 || p->model == 1511)
+ ec = specbos_fcommand(p, "*calc:sprad\r", buf, MAX_RD_SIZE, 4.0,
+ 1, tspec, 0);
+ else
+ ec = specbos_fcommand(p, "*fetch:sprad\r", buf, MAX_RD_SIZE, 4.0,
+ 2+p->nbands+1, tnorm, 0);
if (ec != SPECBOS_OK) {
- if (tries > maxtries) {
- amutex_unlock(p->lock);
- a1logd(p->log, 1, "specbos_fcommand: failed with 0x%x\n",ec);
- return specbos_interp_code((inst *)p, ec);
- }
- continue; /* Retry the fetch */
+ a1logd(p->log, 1, "specbos_fcommand: failed with 0x%x\n",ec);
+ goto try_again; /* Retry the fetch */
}
val->sp.spec_n = p->nbands;
@@ -835,19 +1164,27 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
/* Spectral data is in W/nm/m^2 */
val->sp.norm = 1.0;
cp = buf;
- for (i = -2; i < val->sp.spec_n; i++) {
+ for (i = ii; i < val->sp.spec_n; i++) {
if ((ncp = strchr(cp, '\r')) == NULL) {
- a1logd(p->log, 1, "specbos_read_sample: failed to parse spectra at %d/%d\n",i+1,val->sp.spec_n);
- if (tries > maxtries) {
- amutex_unlock(p->lock);
- return inst_protocol_error;
- }
- continue; /* Retry the fetch and parse */
+ a1logd(p->log, 1, "specbos_read_sample: failed to parse spectra '%s' at %d/%d\n",cp,i+1,val->sp.spec_n);
+ goto try_again; /* Retry the fetch and parse */
}
*ncp = '\000';
if (i >= 0) {
- a1logd(p->log, 6, "sample %d/%d got %f from '%s'\n",i+1,val->sp.spec_n,atof(cp),cp);
- val->sp.spec[i] = 1000.0 * atof(cp); /* Convert to mW/m^2/nm */
+ double wl, sp = -1e6;
+ if (p->model == 1501 || p->model == 1511) {
+ if (sscanf(cp, "%lf %lf", &wl, &sp) != 2)
+ sp = -1e6;
+ } else {
+ if (sscanf(cp, "%lf", &sp) != 1)
+ sp = -1e6;
+ }
+ if (sp == -1e6) {
+ a1logd(p->log, 1, "specbos_read_sample: failed to parse spectra '%s' at %d/%d\n",cp,i+1,val->sp.spec_n);
+ goto try_again; /* Retry the fetch and parse */
+ }
+ a1logd(p->log, 6, "sample %d/%d got %f from '%s'\n",i+1,val->sp.spec_n,sp,cp);
+ val->sp.spec[i] = 1000.0 * sp; /* Convert to mW/m^2/nm */
if (p->mode & inst_mode_ambient)
val->mtype = inst_mrt_ambient;
}
@@ -855,11 +1192,127 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
/* We've parsed correctly, so don't retry */
break;
+
+ try_again:;
+ }
+ if (tries >= maxtries) {
+ a1logd(p->log, 1, "specbos_fcommand: ran out of retries\n");
+ amutex_unlock(p->lock);
+ return inst_protocol_error;
}
a1logd(p->log, 1, "specbos_read_sample: got total %d samples/%d expected in %d tries\n",i,val->sp.spec_n, tries);
+
}
amutex_unlock(p->lock);
+ /* Emulate transmission mode */
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ int i;
+
+ if (p->trans_white.spec_n != val->sp.spec_n
+ || p->trans_white.spec_wl_short != val->sp.spec_wl_short
+ || p->trans_white.spec_wl_long != val->sp.spec_wl_long) {
+ a1logd(p->log, 1, "specbos_read_sample: Emulated transmission mode got mismatched white ref. !");
+ return specbos_interp_code((inst *)p, SPECBOS_INTERNAL_ERROR);
+ }
+
+ for (i = 0; i < p->trans_white.spec_n; i++) {
+ double vv;
+
+ if ((p->trans_white.spec[i] * 3.0) < val->sp.spec[i]) {
+ val->sp.spec[i] = 0.0;
+ } else {
+ val->sp.spec[i] = 100.0 * val->sp.spec[i]/p->trans_white.spec[i];
+ }
+ }
+ val->sp.norm = 100.0;
+
+ /* Do some filtering of the short wavelengths. */
+ /* (This is really compensating for lower instrument sensitivity */
+ /* and an assumed 'A' type illuminant source.) */
+ {
+ int i, ii, j, k;
+ double w, ifw, fw, nn;
+ double wl, we, vv;
+ xspect ts = val->sp; /* Structure copy */
+ double refl;
+
+ /* Do a linear regression to establish and end reflection value */
+ {
+ double s = 0.0, sxx = 0.0, sy = 0.0, sx = 0.0, sxy = 0.0;
+
+ ii = XSPECT_XIX(&val->sp, 400.0); /* End index */
+ for (i = 0; i < ii; i++) {
+ s++;
+ sxx += i * i;
+ sx += i;
+ sy += ts.spec[i];
+ sxy += i * ts.spec[i];
+ }
+ refl = (sxx * sy - sx * sxy)/(s * sxx - sx * sx);
+//printf("~1 [0] = %f, linear regression = %f\n",ts.spec[0],refl);
+ }
+
+ ii = XSPECT_XIX(&val->sp, 500.0); /* End index */
+ ifw = 5.0; /* Initial +/-width */
+ for (i = 0; i < ii; i++) {
+ wl = XSPECT_XWL(&val->sp, i);
+ vv = (ii - i)/(double)ii; /* Reduce width as we increase center wl */
+ fw = pow(vv, 1.7) * ifw;
+ w = nn = vv = 0.0;
+
+ /* Scan down */
+ for (j = 0; ; j++) {
+ w = wl - XSPECT_XWL(&val->sp, i - j); /* Offset we're at */
+ if (w >= fw)
+ break;
+
+ we = fw - w;
+ we = sqrt(we);
+ nn += we;
+
+ if ((i - j) < 0) { /* Reflect */
+ vv += we * (2.0 * refl - ts.spec[i + j]);
+ } else {
+ vv += we * ts.spec[i - j];
+ }
+ }
+
+ /* Scan up */
+ for (j = 0; ; j++) {
+ w = XSPECT_XWL(&val->sp, i + j) - wl; /* Offset we're at */
+ if (w >= fw)
+ break;
+ we = fw - w;
+ we = sqrt(we);
+ nn += we;
+ vv += we * ts.spec[i + j];
+ }
+ vv /= nn;
+ val->sp.spec[i] = vv;
+ }
+ }
+
+ /* Convert to XYZ */
+ if (p->conv == NULL) {
+ p->conv = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigXYZData,
+ icxNoClamp);
+ if (p->conv == NULL) {
+ a1logd(p->log, 1, "specbos_read_sample: Emulated transmission new_xsp2cie() failed");
+ return specbos_interp_code((inst *)p, SPECBOS_INTERNAL_ERROR);
+ }
+ }
+ p->conv->convert(p->conv, val->XYZ, &val->sp);
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+ val->XYZ_v = 1;
+ val->XYZ[0] *= 100.0;
+ val->XYZ[1] *= 100.0;
+ val->XYZ[2] *= 100.0;
+
+ val->mtype = inst_mrt_transmissive;
+ }
+
if (user_trig)
return inst_user_trig;
@@ -879,17 +1332,36 @@ specbos_imp_set_refresh(specbos *p) {
/* Set synchronised read if we should do so */
if (p->refrmode != 0 && p->refrvalid) {
char mes[100];
- if ((rv = specbos_command(p, "*conf:cycmod 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- return rv;
+ if (p->model == 1501 || p->model == 1511) {
+ if ((rv = specbos_command(p, "*para:syncmod 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ return rv;
+ }
+ } else {
+ if ((rv = specbos_command(p, "*conf:cycmod 1\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ return rv;
+ }
}
- sprintf(mes,"*conf:cyctim %f\r",p->refperiod * 1e6);
- if ((rv = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- return rv;
+ if (p->model == 1501 || p->model == 1511) {
+ sprintf(mes,"*para:syncfreq %f\r",1.0/p->refperiod);
+ if ((rv = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ return rv;
+ }
+ } else {
+ sprintf(mes,"*conf:cyctim %f\r",p->refperiod * 1e6);
+ if ((rv = specbos_command(p, mes, buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ return rv;
+ }
}
a1logd(p->log,5,"specbos_imp_set_refresh set refresh rate to %f Hz\n",1.0/p->refperiod);
} else {
- if ((rv = specbos_command(p, "*conf:cycmod 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
- return rv;
+ if (p->model == 1501 || p->model == 1511) {
+ if ((rv = specbos_command(p, "*para:syncmod 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ return rv;
+ }
+ } else {
+ if ((rv = specbos_command(p, "*conf:cycmod 0\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok) {
+ return rv;
+ }
}
a1logd(p->log,5,"specbos_imp_set_refresh set non-refresh mode\n");
}
@@ -920,16 +1392,32 @@ double *ref_rate
return rv;
}
- if ((ec = specbos_fcommand(p, "*contr:cyctim 200 4000\r", buf, MAX_MES_SIZE, 5.0, 1, 2, 0)) != SPECBOS_OK) {
- return specbos_interp_code((inst *)p, ec);
+ if (p->model == 1501 || p->model == 1511) {
+ if ((ec = specbos_fcommand(p, "*meas:flic\r", buf, MAX_MES_SIZE, 30.0, 1, trefr, 0)) != SPECBOS_OK) {
+ return specbos_interp_code((inst *)p, ec);
+ }
+ } else {
+ if ((ec = specbos_fcommand(p, "*contr:cyctim 200 4000\r", buf, MAX_MES_SIZE, 5.0, 1, trefr, 0)) != SPECBOS_OK) {
+ return specbos_interp_code((inst *)p, ec);
+ }
}
- if ((cp = strchr(buf, 'c')) == NULL)
- cp = buf;
- if (sscanf(cp, "cyctim[ms]: %lf ", &refperiod) != 1) {
- a1logd(p->log, 1, "specbos_imp_measure_refresh rate: failed to parse string '%s'\n",icoms_fix(buf));
- *ref_rate = 0.0;
- return inst_misread;
+ if (p->model == 1501 || p->model == 1511) {
+ double ffreq;
+ if (sscanf(buf+1, "%lf ", &ffreq) != 1) {
+ a1logd(p->log, 1, "specbos_imp_measure_refresh rate: failed to parse string '%s'\n",icoms_fix(buf));
+ *ref_rate = 0.0;
+ return inst_misread;
+ }
+ refperiod = 1000.0/ffreq;
+ } else {
+ if ((cp = strchr(buf, 'c')) == NULL)
+ cp = buf;
+ if (sscanf(cp, "cyctim[ms]: %lf ", &refperiod) != 1) {
+ a1logd(p->log, 1, "specbos_imp_measure_refresh rate: failed to parse string '%s'\n",icoms_fix(buf));
+ *ref_rate = 0.0;
+ return inst_misread;
+ }
}
if (refperiod == 0.0)
@@ -1033,6 +1521,12 @@ static inst_code specbos_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal
a_cals |= inst_calt_ref_freq;
}
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ if (p->trans_white.spec_n == 0)
+ n_cals |= inst_calt_trans_vwhite;
+ a_cals |= inst_calt_trans_vwhite;
+ }
+
if (pn_cals != NULL)
*pn_cals = n_cals;
@@ -1047,6 +1541,7 @@ inst_code specbos_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
specbos *p = (specbos *)pp;
@@ -1058,11 +1553,14 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = specbos_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
return ev;
+ a1logd(p->log,4,"specbos_calibrate: needed 0x%x, avaialble 0x%x\n",needed, available);
+
/* Translate inst_calt_all/needed into something specific */
if (*calt == inst_calt_all
|| *calt == inst_calt_needed
@@ -1082,6 +1580,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
/* See if it's a calibration we understand */
if (*calt & ~available & inst_calt_all_mask) {
+ a1logd(p->log,4,"specbos_calibrate: not a calibration we understand\n");
return inst_unsupported;
}
@@ -1100,6 +1599,65 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
*calt &= ~inst_calt_ref_freq;
}
+
+ /* If we are doing a transmission white reference calibrate */
+ if ((*calt & inst_calt_trans_vwhite) != 0
+ && (*calc & inst_calc_cond_mask) == inst_calc_man_trans_white
+ && (p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ inst_mode cmode = p->mode;
+ int i;
+ ipatch val;
+
+ a1logd(p->log,4,"specbos_calibrate: doing transmission white calib\n");
+
+ if (p->mode & inst_mode_ambient)
+ p->mode = inst_mode_emis_ambient | inst_mode_spectral;
+ else
+ p->mode = inst_mode_emis_tele | inst_mode_spectral;
+ p->doing_cal = 1;
+
+ /* Set to average 50 readings */
+ if ((ev = set_average(p, 50, 1)) != inst_ok)
+ return ev;
+
+ if ((ev = specbos_read_sample(pp, "Transmission White", &val, 0)) != inst_ok) {
+ a1logd(p->log,1,"specbos_calibrate: Transmission white cal failed with 0x%x\n",ev);
+ p->mode = cmode;
+ p->doing_cal = 0;
+ set_average(p, 1, 1);
+ return ev;
+ }
+ p->trans_white = val.sp; /* Struct copy */
+
+ /* Restore average */
+ if ((ev = set_average(p, 1, 1)) != inst_ok)
+ return ev;
+
+ // ~~~~9999 check white quality
+
+ *calt &= ~inst_calt_trans_vwhite;
+
+ p->mode = cmode;
+ p->doing_cal = 0;
+ }
+
+ /* Make sure there's the right condition for any remaining calibrations. */
+ if (*calt & inst_calt_trans_vwhite) {/* Transmissvice white for emulated transmission */
+ *idtype = inst_calc_id_none;
+ id[0] = '\000';
+ if ((*calc & inst_calc_cond_mask) != inst_calc_man_trans_white) {
+ *calc = inst_calc_man_trans_white;
+ a1logd(p->log,4,"specbos_calibrate: needs calc 0x%x\n",*calc);
+ return inst_cal_setup;
+ }
+ }
+
+ /* Go around again if we've still got calibrations to do */
+ if (*calt & inst_calt_all_mask) {
+ a1logd(p->log,4,"specbos_calibrate: more calibrations to do\n");
+ return inst_cal_setup;
+ }
+
return inst_ok;
}
@@ -1361,6 +1919,7 @@ specbos_interp_code(inst *pp, int ec) {
case SPECBOS_OVEREXPOSED:
case SPECBOS_UNDEREXPOSED:
+ case SPECBOS_ADAPT_INT_TIME:
return inst_misread | ec;
case SPECBOS_PASSWORD:
@@ -1368,7 +1927,6 @@ specbos_interp_code(inst *pp, int ec) {
case SPECBOS_USERFILE_CHSUM:
case SPECBOS_USERFILE2_CHSUM:
case SPECBOS_USERFILE2_ARG:
- case SPECBOS_ADAPT_INT_TIME:
case SPECBOS_NO_SHUTTER:
case SPECBOS_NO_DARK_MEAS:
case SPECBOS_NO_REF_MEAS:
@@ -1434,6 +1992,8 @@ specbos_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
amutex_del(p->lock);
+ if (p->conv != NULL)
+ p->conv->del(p->conv);
p->vdel(pp);
free(p);
}
@@ -1449,13 +2009,18 @@ inst3_capability *pcap3) {
inst2_capability cap2 = 0;
cap1 |= inst_mode_emis_tele
- | inst_mode_ambient
+ | inst_mode_trans_spot /* Emulated transmission mode diffuse/90 */
+ | inst_mode_trans_spot_a /* Emulated transmission mode 90/diffuse */
| inst_mode_colorimeter
| inst_mode_spectral
| inst_mode_emis_refresh_ovd
| inst_mode_emis_norefresh_ovd
;
+ if (p->model != 1501 && p->model != 1511) {
+ cap1 |= inst_mode_ambient;
+ }
+
/* can inst2_has_sensmode, but not report it asynchronously */
cap2 |= inst2_prog_trig
| inst2_user_trig
@@ -1500,9 +2065,13 @@ int *conf_ix
|| *conf_ix > 1) {
/* Return current configuration measrement modes */
amutex_lock(p->lock);
- if ((ev = specbos_get_diffpos(p, &pos, 0)) != inst_ok) {
- amutex_unlock(p->lock);
- return ev;
+ if (p->model != 1501 && p->model != 1511) {
+ if ((ev = specbos_get_diffpos(p, &pos, 0)) != inst_ok) {
+ amutex_unlock(p->lock);
+ return ev;
+ }
+ } else {
+ pos = 0; /* 1501 & 1511 only have emssion */
}
amutex_unlock(p->lock);
} else {
@@ -1534,6 +2103,7 @@ int *conf_ix
/* Check device measurement mode */
static inst_code specbos_check_mode(inst *pp, inst_mode m) {
+ specbos *p = (specbos *)pp;
inst_mode cap;
if (!pp->gotcoms)
@@ -1547,9 +2117,17 @@ static inst_code specbos_check_mode(inst *pp, inst_mode m) {
if (m & ~cap)
return inst_unsupported;
- /* Only tele emission mode supported */
+ /* 1501 doesn't support ambient */
+ if ((p->model == 1501 || p->model == 1511)
+ && IMODETST(m, inst_mode_emis_ambient)) {
+ return inst_unsupported;
+ }
+
+ /* Only tele emission, ambient and (emulated) transmision modes supported */
if (!IMODETST(m, inst_mode_emis_tele)
- && !IMODETST(m, inst_mode_emis_ambient)) {
+ && !IMODETST(m, inst_mode_trans_spot)
+ && !IMODETST(m, inst_mode_trans_spot_a)
+ && !IMODETST(m, inst_mode_emis_ambient)) {
return inst_unsupported;
}
@@ -1562,12 +2140,13 @@ static inst_code specbos_set_mode(inst *pp, inst_mode m) {
int refrmode;
inst_code ev;
- if ((ev = specbos_check_mode(pp, m)) != inst_ok)
+ if ((ev = specbos_check_mode(pp, m)) != inst_ok) {
+ a1logd(p->log,1,"specbos_set_mode 0x%x invalid\n",m);
return ev;
+ }
p->mode = m;
-
if (p->model != 1201) { /* Can't set refresh mode on 1201 */
/* Effective refresh mode may change */
@@ -1714,8 +2293,7 @@ static inst_code specbos_set_disptype(inst *pp, int ix) {
* error if it hasn't been initialised.
*/
static inst_code
-specbos_get_set_opt(inst *pp, inst_opt_type m, ...)
-{
+specbos_get_set_opt(inst *pp, inst_opt_type m, ...) {
specbos *p = (specbos *)pp;
char buf[MAX_MES_SIZE];
inst_code ev = inst_ok;
@@ -1790,7 +2368,17 @@ specbos_get_set_opt(inst *pp, inst_opt_type m, ...)
if (!p->inited)
return inst_no_init;
- return inst_unsupported;
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/specbos.h b/spectro/specbos.h
index e926c42..5c89fd5 100644
--- a/spectro/specbos.h
+++ b/spectro/specbos.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Fake Error codes */
#define SPECBOS_INTERNAL_ERROR 0xff01 /* Internal software error */
#define SPECBOS_TIMEOUT 0xff02 /* Communication timeout */
@@ -122,11 +126,15 @@
struct _specbos {
INST_OBJ_BASE
+ int bt; /* Bluetooth coms rather than USB/serial flag */
+
amutex lock; /* Command lock */
- int model; /* JETI specbos model number */
+ int model; /* JETI specbos/spectraval model number */
/* 1201 */
/* 1211 */
+ /* 1501 */
+ /* 1511 - has display */
int noXYZ; /* nz if firmware doesn't support fetch*XYZ */
int badCal; /* nz if its been calibrated with a reduced WL range by 3rd party */
@@ -147,6 +155,10 @@ struct _specbos {
double wl_short;
double wl_long;
+ xspect trans_white; /* Synthetic transmission mode white reference */
+ xsp2cie *conv; /* transmission spectral to XYZ conversion */
+ int doing_cal; /* Flag - doing internal calibration measure */
+
/* Other state */
athread *th; /* Diffuser position monitoring thread */
volatile int th_term; /* nz to terminate thread */
@@ -159,6 +171,9 @@ struct _specbos {
/* Constructor */
extern specbos *new_specbos(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
#define SPECBOS_H
#endif /* SPECBOS_H */
diff --git a/spectro/spotread.c b/spectro/spotread.c
index baf1c76..c5ac955 100644
--- a/spectro/spotread.c
+++ b/spectro/spotread.c
@@ -64,7 +64,7 @@
#include "ccss.h"
#include "ccmx.h"
#include "instappsup.h"
-#ifdef ENABLE_USB
+#if !defined(NOT_ALLINSTS) || defined(EN_SPYD2)
# include "spyd2.h"
#endif
@@ -285,10 +285,12 @@ usage(char *diag, ...) {
for (i = 0; ; i++) {
if (paths[i] == NULL)
break;
+#if !defined(NOT_ALLINSTS) || defined(EN_SPYD2)
if ((paths[i]->itype == instSpyder1 && setup_spyd2(0) == 0)
|| (paths[i]->itype == instSpyder2 && setup_spyd2(1) == 0))
fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
else
+#endif
fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
}
} else
@@ -329,6 +331,7 @@ usage(char *diag, ...) {
fprintf(stderr," 6 D65\n");
fprintf(stderr," u U.V. Cut\n");
fprintf(stderr," -E extrafilterfile Apply extra filter compensation file\n");
+ fprintf(stderr," -A N|A|X|G XRGA conversion (default N)\n");
fprintf(stderr," -x Display Yxy instead of Lab\n");
fprintf(stderr," -h Display LCh instead of Lab\n");
fprintf(stderr," -V Show running average and std. devation from ref.\n");
@@ -344,10 +347,17 @@ usage(char *diag, ...) {
if (cap2 & inst2_ccss) {
fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n");
}
+#ifndef SALONEINSTLIB
+ fprintf(stderr," -R fname.sp Preset reference to spectrum\n");
+#endif
fprintf(stderr," -Y r|n Override refresh, non-refresh display mode\n");
fprintf(stderr," -Y R:rate Override measured refresh rate with rate Hz\n");
fprintf(stderr," -Y A Use non-adaptive integration time mode (if available).\n");
+ fprintf(stderr," -Y l|L Test for i1Pro Lamp Drift (l), and remediate it (L)\n");
// fprintf(stderr," -Y U Test i1pro2 UV measurement mode\n");
+#ifndef SALONEINSTLIB
+ fprintf(stderr," -Y W:fname.sp Save white tile ref. spectrum to file\n");
+#endif /* !SALONEINSTLIB */
fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
fprintf(stderr," logfile Optional file to save reading results as text\n");
@@ -373,7 +383,9 @@ int main(int argc, char *argv[]) {
int tele = 0; /* 1 = Use telephoto emissive sub-mode. */
int ambient = 0; /* 1 = Use ambient emissive mode, 2 = ambient flash mode */
int highres = 0; /* Use high res mode if available */
+ int lampdrift = 0; /* i1Pro Lamp Drift test (1) & fix (2) */
int uvmode = 0; /* ~~~ i1pro2 test mode ~~~ */
+ xcalstd calstd = xcalstd_none; /* X-Rite calibration standard */
int refrmode = -1; /* -1 = default, 0 = non-refresh mode, 1 = refresh mode */
double refrate = 0.0; /* 0.0 = default, > 0.0 = override refresh rate */
int nadaptive = 0; /* Use non-apative mode if available */
@@ -387,6 +399,8 @@ int main(int argc, char *argv[]) {
char outname[MAXNAMEL+1] = "\000"; /* Output logfile name */
char ccxxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction/Colorimeter Calibration name */
char filtername[MAXNAMEL+1] = "\000"; /* Filter compensation */
+ char wtilename[MAXNAMEL+1] = "\000"; /* White file spectrum */
+ char psetrefname[MAXNAMEL+1] = "\000"; /* Preset reference spectrum */
FILE *fp = NULL; /* Logfile */
icompaths *icmps = NULL;
int comport = COMPORT; /* COM port used */
@@ -529,12 +543,21 @@ int main(int argc, char *argv[]) {
tillum_set = spec = 1;
tillum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
tillum_set = spec = 1;
tillum = icxIT_custom;
- if (read_xspect(&cust_tillum, na) != 0)
+ if (read_xspect(&cust_tillum, &mt, na) != 0)
usage("Failed to read custom target illuminant spectrum in file '%s'",na);
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Target illuminant '%s' is wrong measurement type",na);
}
-#endif /* SALONEINSTLIB */
+#endif /* !SALONEINSTLIB */
/* Spectral Illuminant type for XYZ computation */
} else if (argv[fa][1] == 'i') {
@@ -566,10 +589,19 @@ int main(int argc, char *argv[]) {
illum_set = spec = 1;
illum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
illum_set = spec = 1;
illum = icxIT_custom;
- if (read_xspect(&cust_illum, na) != 0)
+ if (read_xspect(&cust_illum, &mt, na) != 0)
usage("Unable to read custom illuminant file '%s'",na);
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Custom illuminant '%s' is wrong measurement type",na);
}
#else /* SALONEINSTLIB */
} else
@@ -600,7 +632,7 @@ int main(int argc, char *argv[]) {
emiss = 0;
trans = 1;
tele = 0;
- ambient = 0;
+ ambient = 0; /* Default normal diffuse/90 geometry trans. */
/* Request emissive measurement */
} else if (argv[fa][1] == 'e' || argv[fa][1] == 'd') {
@@ -642,10 +674,14 @@ int main(int argc, char *argv[]) {
/* Request ambient measurement */
} else if (argv[fa][1] == 'a') {
- emiss = 1;
- trans = 0;
- tele = 0;
- ambient = 1;
+ if (trans) {
+ ambient = 1; /* Alternate 90/diffuse geometry */
+ } else {
+ emiss = 1;
+ trans = 0;
+ tele = 0;
+ ambient = 1;
+ }
/* Request ambient flash measurement */
} else if (argv[fa][1] == 'f') {
@@ -675,6 +711,21 @@ int main(int argc, char *argv[]) {
if (na == NULL) usage("Paramater expected following -E");
strncpy(filtername,na,MAXNAMEL-1); filtername[MAXNAMEL-1] = '\000';
+ /* XRGA conversion */
+ } else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -A");
+ if (na[0] == 'N')
+ calstd = xcalstd_none;
+ else if (na[0] == 'A')
+ calstd = xcalstd_xrga;
+ else if (na[0] == 'X')
+ calstd = xcalstd_xrdi;
+ else if (na[0] == 'G')
+ calstd = xcalstd_gmdi;
+ else
+ usage("Paramater after -A '%c' not recognized",na[0]);
+
/* Show Yxy */
} else if (argv[fa][1] == 'x') {
doYxy = 1;
@@ -725,6 +776,15 @@ int main(int argc, char *argv[]) {
if (na == NULL) usage("Parameter expected after -K");
strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+#ifndef SALONEINSTLIB
+ /* Preset reference spectrum */
+ } else if (argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL)
+ usage("-R fname.sp syntax incorrect");
+ strncpy(psetrefname,na,MAXNAMEL-1); psetrefname[MAXNAMEL-1] = '\000';
+#endif
+
/* Extra flags */
} else if (argv[fa][1] == 'Y') {
if (na == NULL)
@@ -742,9 +802,25 @@ int main(int argc, char *argv[]) {
refrate = atof(na+2);
if (refrate < 5.0 || refrate > 150.0)
usage("-Y R:rate %f Hz not in valid range",refrate);
+
+#ifndef SALONEINSTLIB
+ /* Save white tile reference spectrum to a file */
+ } else if (na[0] == 'W') {
+ if (na[1] != ':')
+ usage("-Y W:fname.sp syntax incorrect");
+ strncpy(wtilename,&na[2],MAXNAMEL-1); wtilename[MAXNAMEL-1] = '\000';
+#endif /* !SALONEINSTLIB */
+
+ /* i1Pro lamp drift test & fix */
+ } else if (na[0] == 'l') {
+ lampdrift = 1;
+ } else if (na[0] == 'L') {
+ lampdrift = 2;
+
/* ~~~ i1pro2 test code ~~~ */
} else if (na[0] == 'U') {
uvmode = 1;
+
} else {
usage("-Y parameter '%c' not recognised",na[0]);
}
@@ -755,7 +831,7 @@ int main(int argc, char *argv[]) {
fa = nfa;
if (na == NULL) usage("Parameter expected after -W");
if (na[0] == 'n' || na[0] == 'N')
- fc = fc_none;
+ fc = fc_None;
else if (na[0] == 'h' || na[0] == 'H')
fc = fc_Hardware;
else if (na[0] == 'x' || na[0] == 'X')
@@ -850,6 +926,135 @@ int main(int argc, char *argv[]) {
return -1;
}
+ /* Check i1Pro lamp drift, and remediate if it is too large */
+ /* (Hmm. If cooltime is too long, drift appears to be worse
+ after remediation. It's not clear why, but it returns
+ to expected values once instrument has truly cooled down (i.e. 2+min ?)
+ */
+ if (lampdrift) {
+ int pass = 0;
+ double remtime = 0.0;
+ int cooltime = 30;
+
+ if (it->itype != instI1Pro
+ && it->itype != instI1Pro2) {
+ printf("LampDrift is only applicable to i1Pro instrument");
+ }
+
+ /* Disable initial calibration of machine if selected */
+ if (nocal != 0) {
+ if ((rv = it->get_set_opt(it,inst_opt_noinitcalib, 0)) != inst_ok) {
+ printf("Setting no-initial calibrate failed with '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ printf("Disable initial-calibrate not supported\n");
+ }
+ }
+
+ if ((rv = it->get_set_opt(it, inst_opt_trig_prog)) != inst_ok)
+ error("Setting trigger mode failed with error :'%s' (%s)",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+
+ for (pass = 0; pass < 2; pass++) {
+ ipatch val;
+ double dl, maxdl = -100.0, de, maxde = -100.0;
+ int ii;
+
+ printf("\nDoing Lamp Drift check - place instrument on calibration tile\n");
+
+ /* Do any needed calibration before the user places the instrument on a desired spot */
+ if (it->needs_calibration(it) & inst_calt_n_dfrble_mask) {
+ inst_code ev;
+
+ printf("\nNeed a calibration before continuing\n");
+
+ ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, doone);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ error("Got abort or error from calibration");
+ }
+ }
+
+#ifndef NEVER
+ /* Ensure lamp has cooled down */
+ printf("\nAllowing lamp to cool\n");
+ for (i = cooltime; i > 0; i--) {
+ msec_sleep(1000);
+ printf("\r%d ",i); fflush(stdout);
+ }
+ printf("\r0 \n");
+#endif
+
+ printf("\nChecking Lamp Drift\n");
+ /* Measure 1 spot and save as ref */
+ if ((rv = it->read_sample(it, "SPOT", &val, instNoClamp)) != inst_ok) {
+ error("Read sample failed with '%s' (%s)",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ }
+ if (val.XYZ_v == 0) error("Instrument didn't return XYZ value");
+ icmXYZ2Lab(&icmD50_100, rLab, val.XYZ);
+
+ // Until measurement is stable, or 30 measurements
+ // Read and save max DE
+
+ /* 30 trials, or no new biggest in 4 measurements */
+ for (ii = 100, i = 0; i < 40 && (i < 10 || (i - ii) < 6) ; i++) {
+ if ((rv = it->read_sample(it, "SPOT", &val, instNoClamp)) != inst_ok) {
+ error("Read sample failed with '%s' (%s)",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ }
+ if (val.XYZ_v == 0) error("Instrument didn't return XYZ value");
+ icmXYZ2Lab(&icmD50_100, Lab, val.XYZ);
+
+ dl = Lab[0] - rLab[0];
+ de = icmLabDE(Lab, rLab);
+
+ /* Keep going while dl is rising */
+ if (dl > maxdl) {
+ maxdl = dl;
+ ii = i;
+ }
+ if (de > maxde) {
+ maxde = de;
+ printf("\r%1.3f DE",de); fflush(stdout);
+ }
+ }
+
+ // Print DE
+// printf("\nLamp Drift Delta E = %f\n",maxde);
+
+ if (lampdrift == 1) {
+ printf("\nDrift test complete - %s\n", maxde >= 0.09 ? "Needs Fixing!" : "OK");
+ break;
+ }
+
+ if (pass > 0) {
+ printf("\nDrift test & fix complete\n");
+ break;
+ }
+
+ if (maxde >= 0.09)
+ remtime = 60.0;
+ else if (maxde >= 0.12)
+ remtime = 90.0;
+ else if (maxde > 0.20)
+ remtime = 120.0;
+
+ if (remtime > 0.0) {
+ printf("\nDoing %.0f seconds of remediation\n",remtime);
+ // Do remediation */
+ if ((rv = it->get_set_opt(it, inst_opt_lamp_remediate, remtime)) != inst_ok) {
+ error("Remediating Lamp Drift failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ }
+ cooltime = 45;
+ } else {
+ printf("\nDrift is OK\n");
+ break;
+ }
+ }
+
+ goto done;
+ }
+
/* Configure the instrument mode */
{
int ccssset = 0;
@@ -873,17 +1078,26 @@ int main(int argc, char *argv[]) {
}
if (trans) {
- if (!IMODETST(cap, inst_mode_trans_spot)
- || it->check_mode(it, inst_mode_trans_spot) != inst_ok) {
- printf("Need transmission spot capability,\n");
- printf("and instrument doesn't support it\n");
- it->del(it);
- return -1;
+ /* Alternate geometry - 90/diffuse */
+ if (ambient) {
+ if (it->check_mode(it, inst_mode_trans_spot_a) != inst_ok) {
+ printf("Need transmission spot (alt) capability,\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+ /* Normal geometry - diffuce/90 */
+ } else {
+ if (it->check_mode(it, inst_mode_trans_spot) != inst_ok) {
+ printf("Need transmission spot capability,\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
}
} else if (ambient == 1) {
- if (!IMODETST(cap, inst_mode_emis_ambient)
- || it->check_mode(it, inst_mode_emis_ambient) != inst_ok) {
+ if (it->check_mode(it, inst_mode_emis_ambient) != inst_ok) {
printf("Requested ambient light capability,\n");
printf("and instrument doesn't support it.\n");
return -1;
@@ -895,8 +1109,7 @@ int main(int argc, char *argv[]) {
}
} else if (ambient == 2) {
- if (!IMODETST(cap, inst_mode_emis_ambient_flash)
- || it->check_mode(it, inst_mode_emis_ambient_flash) != inst_ok) {
+ if (it->check_mode(it, inst_mode_emis_ambient_flash) != inst_ok) {
printf("Requested ambient flash capability,\n");
printf("and instrument doesn't support it.\n");
it->del(it);
@@ -912,22 +1125,20 @@ int main(int argc, char *argv[]) {
} else if (emiss || tele) {
/* If there is a tele mode but no emission, use tele */
- if (!IMODETST(cap, inst_mode_emis_spot)
- && IMODETST(cap, inst_mode_emis_tele)) {
+ if (it->check_mode(it, inst_mode_emis_spot) != inst_ok
+ && it->check_mode(it, inst_mode_emis_tele) == inst_ok) {
tele = 1;
}
if (tele) {
- if (!IMODETST(cap, inst_mode_emis_tele)
- || it->check_mode(it, inst_mode_emis_tele) != inst_ok) {
+ if (it->check_mode(it, inst_mode_emis_tele) != inst_ok) {
printf("Need telephoto spot capability\n");
printf("and instrument doesn't support it\n");
it->del(it);
return -1;
}
} else {
- if (!IMODETST(cap, inst_mode_emis_spot)
- || it->check_mode(it, inst_mode_emis_spot) != inst_ok) {
+ if (it->check_mode(it, inst_mode_emis_spot) != inst_ok) {
printf("Need emissive spot capability\n");
printf("and instrument doesn't support it\n");
it->del(it);
@@ -941,16 +1152,15 @@ int main(int argc, char *argv[]) {
nadaptive = 0;
}
}
- if (refrmode >= 0 && !IMODETST(cap, inst_mode_emis_refresh_ovd)
- && !IMODETST(cap, inst_mode_emis_norefresh_ovd)) {
+ if (refrmode >= 0 && it->check_mode(it, inst_mode_emis_refresh_ovd) != inst_ok
+ && it->check_mode(it, inst_mode_emis_norefresh_ovd) != inst_ok) {
if (verb) {
printf("Requested refresh mode override and instrument doesn't support it (ignored)\n");
refrmode = -1;
}
}
} else {
- if (!IMODETST(cap, inst_mode_ref_spot)
- || it->check_mode(it, inst_mode_ref_spot) != inst_ok) {
+ if (it->check_mode(it, inst_mode_ref_spot) != inst_ok) {
printf("Need reflection spot reading capability,\n");
printf("and instrument doesn't support it\n");
it->del(it);
@@ -1007,12 +1217,15 @@ int main(int argc, char *argv[]) {
/* Set it to the appropriate mode */
/* Should look at instrument type & user spec ??? */
- if (trans)
- smode = mode = inst_mode_trans_spot;
- else if (ambient == 1 && IMODETST(cap, inst_mode_emis_ambient)
+ if (trans) {
+ if (ambient)
+ smode = mode = inst_mode_trans_spot_a;
+ else
+ smode = mode = inst_mode_trans_spot;
+ } else if (ambient == 1
&& it->check_mode(it, inst_mode_emis_ambient) == inst_ok)
smode = mode = inst_mode_emis_ambient;
- else if (ambient == 2 && IMODETST(cap, inst_mode_emis_ambient_flash)
+ else if (ambient == 2
&& it->check_mode(it, inst_mode_emis_ambient_flash) == inst_ok)
smode = mode = inst_mode_emis_ambient_flash;
else if (tele) // Hmm. What about tele flash ?
@@ -1021,8 +1234,7 @@ int main(int argc, char *argv[]) {
smode = mode = inst_mode_emis_spot;
else {
smode = mode = inst_mode_ref_spot;
- if (IMODETST(cap, inst_mode_s_ref_spot)
- && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok)
+ if (it->check_mode(it, inst_mode_s_ref_spot) == inst_ok)
smode = inst_mode_s_ref_spot;
}
@@ -1087,6 +1299,15 @@ int main(int argc, char *argv[]) {
}
}
+ /* set XRGA conversion */
+ if (calstd != xcalstd_none) {
+ if ((rv = it->get_set_opt(it, inst_opt_set_xcalstd, calstd)) != inst_ok) {
+ printf("Setting calibration standard not supported by instrument\n");
+ it->del(it);
+ return -1;
+ }
+ }
+
/* Colorimeter Correction Matrix */
if (ccxxname[0] != '\000') {
ccss *cs = NULL;
@@ -1242,6 +1463,26 @@ int main(int argc, char *argv[]) {
inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
}
+#ifndef SALONEINSTLIB
+ /* Save reference white tile reflectance spectrum */
+ if (wtilename[0] != '\000') {
+ xspect sp;
+
+ if ((rv = it->get_set_opt(it, inst_opt_get_cal_tile_sp, &sp)) != inst_ok) {
+ printf("\nGetting reference white tile spectrum failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ if (write_xspect(wtilename, inst_mrt_reflective, &sp) != 0)
+ error("Failed to save spectrum to file '%s'",wtilename);
+
+ if (verb)
+ printf("Saved reference white tile spectrum to '%s'\n",wtilename);
+ }
+#endif /* !SALONEINSTLIB */
+
#ifdef DEBUG
printf("About to enter read loop\n");
#endif
@@ -1253,9 +1494,9 @@ int main(int argc, char *argv[]) {
it->set_uicallback(it, uicallback, NULL);
}
- if (spec) {
+ if (spec || psetrefname[0] != '\000') {
/* Any non-illuminated mode has no illuminant */
- if (emiss || tele || ambient)
+ if (emiss || ambient)
illum = icxIT_none;
/* Create a spectral conversion object */
@@ -1274,6 +1515,43 @@ int main(int argc, char *argv[]) {
}
}
+#ifndef SALONEINSTLIB
+ /* Load preset reference spectrum */
+ if (psetrefname[0] != '\000') {
+ inst_meas_type mt;
+
+ if (read_xspect(&rsp, &mt, psetrefname) != 0)
+ error("Failed to read spectrum from file '%s'",psetrefname);
+
+ if (!emiss && !ambient) {
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_transmissive
+ && mt != inst_mrt_reflective)
+ error("Reference reflectance spectrum '%s' is wrong measurement type",psetrefname);
+ } else {
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Reference reflectance spectrum '%s' is wrong measurement type",psetrefname);
+ }
+
+ if (verb)
+ printf("Loaded reference spectrum from '%s'\n",psetrefname);
+
+ sp2cie->convert(sp2cie, rXYZ, &rsp);
+
+ if (!(emiss || tele || ambient)) {
+ for (j = 0; j < 3; j++)
+ rXYZ[j] *= 100.0; /* 0..100 scale */
+ }
+ icmXYZ2Lab(&icmD50_100, rLab, rXYZ);
+ if (verb)
+ printf("Preset ref. XYZ %f %f %f, Lab %f %f %f\n", rXYZ[0], rXYZ[1], rXYZ[2], rLab[0], rLab[1], rLab[2]);
+ }
+#endif
+
/* Hold table */
if (cap2 & inst2_xy_holdrel) {
for (;;) { /* retry loop */
@@ -1338,8 +1616,7 @@ int main(int argc, char *argv[]) {
#endif // NEVER
- if (savdrd != -1 && IMODETST(cap, inst_mode_s_ref_spot)
- && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok) {
+ if (savdrd != -1 && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok) {
inst_stat_savdrd sv;
savdrd = 0;
@@ -1670,7 +1947,8 @@ int main(int argc, char *argv[]) {
break;
}
printf("\n");
- if (it->icom->port_type(it->icom) == icomt_serial) {
+ if ((it->icom->port_type(it->icom) & icomt_serial)
+ && !(it->icom->port_attr(it->icom) & icomt_fastserial)) {
/* Allow retrying at a lower baud rate */
int tt = it->last_scomerr(it);
if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
@@ -1792,7 +2070,7 @@ int main(int argc, char *argv[]) {
printf("\nEnter filename (ie. xxxx.sp): "); fflush(stdout);
if (getns(buf, 500) != NULL && strlen(buf) > 0) {
- if(write_xspect(buf, &tsp))
+ if(write_xspect(buf, val.mtype, &tsp))
printf("\nWriting file '%s' failed\n",buf);
else
printf("\nWriting file '%s' succeeded\n",buf);
@@ -2079,7 +2357,7 @@ int main(int argc, char *argv[]) {
ymin = 0.0;
ymax = 120.0;
}
- do_plot_x(xx, yy, rLab[0] >= -1.0 ? yr : NULL, NULL, nn, 1,
+ do_plot_x(xx, yy, NULL, rLab[0] >= -1.0 ? yr : NULL, nn, 1,
xmin, xmax, ymin, ymax, 2.0);
}
#endif /* !SALONEINSTLIB */
@@ -2333,12 +2611,18 @@ int main(int argc, char *argv[]) {
}
#ifndef SALONEINSTLIB
if (val.sp.spec_n > 0 && (ambient || doCCT)) {
- int invalid = 0;
+ int i, invalid = 0;
double RR[14];
double cri;
cri = icx_CIE1995_CRI(&invalid, RR, &sp);
printf(" Color Rendering Index (Ra) = %.1f [ R9 = %.1f ]%s\n",
cri, RR[9-1], invalid ? " (Invalid)" : "");
+ for (i = 0; i < 14; i++) {
+ printf(" R%d%s = %.1f", i+1, i < 9 ? " " : "", RR[i]);
+ if (i == 6)
+ printf("\n");
+ }
+ printf("\n");
}
if (val.sp.spec_n > 0 && (ambient || doCCT)) {
int invalid = 0;
@@ -2380,6 +2664,8 @@ int main(int argc, char *argv[]) {
} /* Next reading */
+done:;
+
/* Release paper */
if (cap2 & inst2_xy_holdrel) {
it->xy_clear(it);
diff --git a/spectro/spyd2.c b/spectro/spyd2.c
index 6833e89..85a2d7f 100644
--- a/spectro/spyd2.c
+++ b/spectro/spyd2.c
@@ -819,10 +819,12 @@ spyd2_GetReading_ll(
msec_sleep(500);
a1logd(p->log, 1, "spyd2_GetReading_ll: reading retry with ICOM err 0x%x\n",se);
-#ifdef DO_RESETEP /* Do the miscelanous resetep()'s */
- a1logd(p->log, 1, "spyd2_GetReading_ll: resetting end point\n");
- p->icom->usb_resetep(p->icom, 0x81);
- msec_sleep(1); /* Let device recover ? */
+#ifdef DO_RESETEP /* Do the miscelanous resetep()'s every second time */
+ if ((retr & 1) == 0) {
+ a1logd(p->log, 1, "spyd2_GetReading_ll: resetting end point\n");
+ p->icom->usb_resetep(p->icom, 0x81);
+ msec_sleep(1); /* Let device recover ? */
+ }
#endif /* DO_RESETEP */
} /* End of whole command retries */
@@ -2888,7 +2890,7 @@ spyd2_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
#endif
/* On OS X the Spyder 2 can't close properly */
-#if defined(__APPLE__) /* OS X*/
+#if defined(UNIX_APPLE) /* OS X*/
if (p->itype == instSpyder1
|| p->itype == instSpyder2) {
usbflags |= icomuf_reset_before_close; /* The spyder 2 USB is buggy ? */
@@ -3255,6 +3257,7 @@ static inst_code spyd2_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
spyd2 *p = (spyd2 *)pp;
@@ -3266,6 +3269,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
if ((ev = spyd2_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
@@ -4060,7 +4064,18 @@ spyd2_get_set_opt(inst *pp, inst_opt_type m, ...) {
if (trans_time_prop != NULL) *trans_time_prop = p->led_trans_time_prop;
return inst_ok;
}
- return inst_unsupported;
+
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
}
/* Constructor */
diff --git a/spectro/spyd2.h b/spectro/spyd2.h
index 0588b9b..318ed7c 100644
--- a/spectro/spyd2.h
+++ b/spectro/spyd2.h
@@ -37,6 +37,10 @@
#include "inst.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Note: update spyd2_interp_error() and spyd2_interp_code() in spyd2.c */
/* if anything of these #defines are added or subtracted */
@@ -178,5 +182,9 @@ extern spyd2 *new_spyd2(icoms *icom, instType itype);
/* Return 1 if Spyder firmware is available */
extern int setup_spyd2(int id);
+#ifdef __cplusplus
+ }
+#endif
+
#define SPYD2_H
#endif /* SPYD2_H */
diff --git a/spectro/ss.c b/spectro/ss.c
index 837e264..260df4a 100644
--- a/spectro/ss.c
+++ b/spectro/ss.c
@@ -43,17 +43,20 @@
There is a bug or limitation with using -N to skip the calibration
when using any of the emissive modes - the readings end up being nearly zero.
+ When -N is used, doing a manual calibration (i.e. spotread 'k') doesn't
+ work.
+
We aren't saving the spectrolino fake tranmission white reference in
a calibration file, so -N doesn't work with it.
You can't trigger a calibration reading using the instrument switch.
- You should be able to do use the table enter key anywhere the user
+ You should be able to use the table enter key anywhere the user
is asked to hit a key.
The corner positioning could be smarter.
- The SpectroscanT transmission cal. merely reminds the user (vie verbose)
+ The SpectroscanT transmission cal. merely reminds the user (via verbose)
that it is assuming the correct apatture, rather than given them
a chance to change it.
@@ -78,6 +81,7 @@
#include "conv.h"
#include "icoms.h"
#include "ss.h"
+#include "xrga.h"
/* Default flow control */
#define DEFFC fc_Hardware
@@ -97,6 +101,17 @@ char* filter_desc[] = {
"Custon Filter"
};
+/* Filter id */
+inst_calc_id_type filter_id[] = {
+ inst_calc_id_filt_unkn,
+ inst_calc_id_filt_none,
+ inst_calc_id_filt_pol,
+ inst_calc_id_filt_D65,
+ inst_calc_id_filt_unkn,
+ inst_calc_id_filt_UV,
+ inst_calc_id_filt_cust
+};
+
#define SS_REF_CAL_COUNT 50
#define SS_TRANS_CAL_COUNT 10
@@ -165,7 +180,7 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
fcc1 = ss_ctt_ProtokolWithHardwareHS;
fcc2 = ss_hst_Hardware;
} else {
- fc = fc_none;
+ fc = fc_None;
fcc1 = ss_ctt_ProtokolWithoutXonXoff;
fcc2 = ss_hst_None;
}
@@ -195,7 +210,7 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* Until we time out, find the correct baud rate */
for (i = ci; clock() < etime;) {
a1logd(p->log, 4, "ss_init_coms: trying baud rate %d\n",i);
- if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
+ if ((se = p->icom->set_ser_port(p->icom, fc_None, brt[i], parity_none,
stop_1, length_8)) != ICOM_OK) {
a1logd(p->log, 1, "ss_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
p->snerr = icoms2ss_err(se);
@@ -258,8 +273,24 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
return ss_inst_err(p);
}
+ /* Make sure the Spectrolino is still talking to us. */
+ ss_init_send(p);
+ ss_add_soreq(p, ss_ParameterRequest);
+ ss_command(p, SH_TMO);
+
+ if (ss_sub_1(p) != ss_ParameterAnswer) { /* Comms failed */
+ a1logd(p->log, 1, "ss_init_coms: spectrolino, instrument isn't communicating after final coms setup");
+ return inst_coms_fail;
+ }
+
} else { /* Spectroscan */
+ /* Reset the Spectroscan, in case Spectrolino got messed up. */
+ if ((ev = ss_do_ScanInitializeDevice(p)) != inst_ok) {
+ a1logd(p->log, 1, "ss_init_coms: Spectroscan reset failed ICOM err 0x%x\n",ev);
+ return ev;
+ }
+
ss_do_SetDeviceOnline(p); /* Put the device online */
/* Make sure other communication parameters are right */
@@ -275,9 +306,19 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
return ss_inst_err(p);
}
- /* Make sure the Spectrolino is talking to us. */
+ /* Make sure the Spectroscan is still talking to us. */
+ ss_init_send(p);
+ ss_add_ssreq(p, ss_OutputStatus);
+ ss_command(p, SH_TMO);
+
+ if (ss_sub_1(p) != ss_AnsPFX) { /* Comms failed */
+ a1logd(p->log, 1, "ss_init_coms: spectroscan, instrument isn't communicating after final coms setup");
+ return inst_coms_fail;
+ }
+
+ /* Make sure the Spectrolino is talking to Spectroscan. */
if ((ev = ss_do_ScanSpectrolino(p)) != inst_ok) {
- a1logd(p->log, 1, "ss_init_coms: spectroscan, instrument isn't communicating ICOM err 0x%x\n",se);
+ a1logd(p->log, 1, "ss_init_coms: Spectrolino isn't communicating with Spectroscan ICOM err 0x%x\n",ev);
return ev;
}
}
@@ -322,7 +363,7 @@ ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
|| strncmp(devn, "Spectrolino",11) != 0)
return inst_unknown_model;
- if (p->itype == instUnknown) /* No SpectrScan */
+ if (p->itype == instUnknown) /* No SpectroScan */
p->itype = instSpectrolino;
}
}
@@ -387,6 +428,7 @@ static void ss_determine_capabilities(ss *p) {
/* return non-zero on an error, with dtp error code */
static inst_code
ss_init_inst(inst *pp) {
+ char *envv;
ss *p = (ss *)pp;
inst_code rv = inst_ok;
@@ -395,6 +437,19 @@ ss_init_inst(inst *pp) {
if (p->gotcoms == 0)
return inst_internal_error; /* Must establish coms before calling init */
+ p->native_calstd = xcalstd_gmdi; /* Native is GMDI */
+ p->target_calstd = xcalstd_native; /* Default to native calibration */
+
+ /* Honor Environment override */
+ if ((envv = getenv("ARGYLL_XCALSTD")) != NULL) {
+ if (strcmp(envv, "XRGA") == 0)
+ p->target_calstd = xcalstd_xrga;
+ else if (strcmp(envv, "XRDI") == 0)
+ p->target_calstd = xcalstd_xrdi;
+ else if (strcmp(envv, "GMDI") == 0)
+ p->target_calstd = xcalstd_gmdi;
+ }
+
/* Reset the instrument to a known state */
if (p->itype != instSpectrolino) {
@@ -409,8 +464,9 @@ ss_init_inst(inst *pp) {
return rv;
if ((rv = ss_do_ReleasePaper(p)) != inst_ok)
return rv;
- if ((rv = ss_do_InitMotorPosition(p)) != inst_ok)
- return rv;
+ /* Skip this since we did a ss_do_ScanInitializeDevice() */
+// if ((rv = ss_do_InitMotorPosition(p)) != inst_ok)
+// return rv;
if (p->log->verb) {
char dn[19]; /* Device name */
@@ -642,7 +698,7 @@ struct _inst *pp) {
return rv;
}
-static inst_code ss_calibrate_imp(ss *p, inst_cal_type *calt, inst_cal_cond *calc, char id[CALIDLEN]);
+static inst_code ss_calibrate_imp(ss *p, inst_cal_type *calt, inst_cal_cond *calc, inst_calc_id_type *idtype, char id[CALIDLEN]);
/* Read a sheet full of patches using xy mode */
/* Return the inst error code */
@@ -725,10 +781,11 @@ ipatch *vals) { /* Pointer to array of values */
if ( (p->need_wd_cal || p->need_t_cal) && p->noinitcalib == 0) {
inst_cal_type calt = inst_calt_needed;
inst_cal_cond calc = inst_calc_none;
+ inst_calc_id_type idtype;
char id[CALIDLEN];
/* We expect this to be automatic, but handle as if it mightn't be */
- if ((rv = ss_calibrate_imp(p, &calt, &calc, id)) != inst_ok) {
+ if ((rv = ss_calibrate_imp(p, &calt, &calc, &idtype, id)) != inst_ok) {
if (rv == inst_cal_setup)
return inst_needs_cal; /* Not automatic, needs a manual setup */
if (try < notries) {
@@ -819,6 +876,11 @@ ipatch *vals) { /* Pointer to array of values */
}
}
+ /* Apply any XRGA conversion */
+ ipatch_convert_xrga(vals, npatch,
+ p->filt == ss_aft_PolFilter ? xcalstd_pol : xcalstd_nonpol,
+ p->target_calstd, p->native_calstd, instClamp);
+
return rv;
}
@@ -945,10 +1007,11 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if ((p->need_wd_cal || p->need_t_cal) && p->noinitcalib == 0) {
inst_cal_type calt = inst_calt_needed;
inst_cal_cond calc = inst_calc_none;
+ inst_calc_id_type idtype;
char id[CALIDLEN];
/* This could be automatic or need manual intervention */
- if ((rv = ss_calibrate_imp(p, &calt, &calc, id)) != inst_ok) {
+ if ((rv = ss_calibrate_imp(p, &calt, &calc, &idtype, id)) != inst_ok) {
if (rv == inst_cal_setup) {
return inst_needs_cal; /* Not automatic, needs a manual setup */
}
@@ -1269,7 +1332,8 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
/* spectrum data is returned only if requested */
- if (p->mode & inst_mode_spectral) {
+ if (p->mode & inst_mode_spectral
+ || XCALSTD_NEEDED(p->target_calstd, p->native_calstd)) {
ss_st rst; /* Return Spectrum Type (Reflectance/Density) */
ss_rvt rvf; /* Return Reference Valid Flag */
ss_aft af; /* Return filter being used (None/Pol/D65/UV/custom */
@@ -1294,6 +1358,12 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
}
}
}
+
+ /* Apply any XRGA conversion to the measurement */
+ ipatch_convert_xrga(val, 1,
+ p->filt == ss_aft_PolFilter ? xcalstd_pol : xcalstd_nonpol,
+ p->target_calstd, p->native_calstd, clamp);
+
if (user_trig)
return inst_user_trig;
return rv;
@@ -1342,6 +1412,7 @@ static inst_code ss_calibrate_imp(
ss *p,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
inst_code rv = inst_ok;
@@ -1350,6 +1421,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
ss_owrt owr; /* Original white reference */
inst_cal_type needed, available;
+ *idtype = inst_calc_id_none;
id[0] = '\000';
a1logd(p->log, 3, "ss calibrate called with calt = 0x%x, condition 0x%x, need w %d, t %d\n", *calt, *calc, p->need_wd_cal, p->need_t_cal);
@@ -1407,6 +1479,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
/* Get the name of the expected white reference */
if ((rv = so_do_WhiteReferenceRequest(p, p->filt, &afilt, sp, &owr, id)) != inst_ok)
return rv;
+ *idtype = inst_calc_id_ref_sn;
if (p->noinitcalib == 0) {
@@ -1457,6 +1530,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
a1logd(p->log, 3, "got filt %d, want %d\n",af,p->filt);
+ *idtype = filter_id[p->filt];
strcpy(id, filter_desc[p->filt]);
*calc = inst_calc_change_filter;
return inst_cal_setup;
@@ -1543,6 +1617,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (i < 36) {
*calc = inst_calc_message;
+ *idtype = inst_calc_id_trans_wl;
strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
rv = inst_ok;
}
@@ -1596,6 +1671,7 @@ inst_code ss_calibrate(
inst *pp,
inst_cal_type *calt, /* Calibration type to do/remaining */
inst_cal_cond *calc, /* Current condition/desired condition */
+inst_calc_id_type *idtype, /* Condition identifier type */
char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
) {
ss *p = (ss *)pp;
@@ -1605,7 +1681,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
if (!p->inited)
return inst_no_init;
- return ss_calibrate_imp(p, calt, calc, id);
+ return ss_calibrate_imp(p, calt, calc, idtype, id);
}
/* Insert a compensation filter in the instrument readings */
@@ -1629,7 +1705,7 @@ char *filtername
} else {
xspect sp;
int i;
- if (read_xspect(&sp, filtername) != 0) {
+ if (read_xspect(&sp, NULL, filtername) != 0) {
return inst_wrong_setup;
}
if (sp.spec_n != 36 || sp.spec_wl_short != 380.0 || sp.spec_wl_long != 730.0) {
@@ -1944,6 +2020,35 @@ ss_get_set_opt(inst *pp, inst_opt_type m, ...) {
break;
}
return inst_unsupported;
+
+ /* Set the current xcalstd */
+ } else if (m == inst_opt_set_xcalstd) {
+ xcalstd standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd);
+ va_end(args);
+
+ p->target_calstd = standard;
+
+ return inst_ok;
+
+ /* Get the current effective xcalstd */
+ } else if (m == inst_opt_get_xcalstd) {
+ xcalstd *standard;
+ va_list args;
+
+ va_start(args, m);
+ standard = va_arg(args, xcalstd *);
+ va_end(args);
+
+ if (p->target_calstd == xcalstd_native)
+ *standard = p->native_calstd; /* If not overridden */
+ else
+ *standard = p->target_calstd; /* Overidden std. */
+
+ return inst_ok;
}
/* Record the trigger mode */
@@ -2002,6 +2107,34 @@ ss_get_set_opt(inst *pp, inst_opt_type m, ...) {
return inst_ok;
}
+ /* Return the white calibration tile spectrum for current filter */
+ if (m == inst_opt_get_cal_tile_sp) {
+ ss_aft raf;
+ ss_owrt owr;
+ xspect *sp;
+ char dtn[19];
+ inst_code rv;
+ va_list args;
+ int i;
+
+ va_start(args, m);
+ sp = va_arg(args, xspect *);
+ va_end(args);
+
+ /* Queries the spectra of the white tile reference for the desired filter */
+ if ((rv = so_do_WhiteReferenceRequest(p, p->filt, &raf, sp->spec, &owr, dtn)) != inst_ok)
+ return rv;
+
+ sp->spec_n = 36;
+ sp->spec_wl_short = 380;
+ sp->spec_wl_long = 730;
+ sp->norm = 100.0;
+ for (i = 0; i < sp->spec_n; i++)
+ sp->spec[i] *= 100.0;
+
+ return inst_ok;
+ }
+
/* Use default implementation of other inst_opt_type's */
{
va_list args;
diff --git a/spectro/ss.h b/spectro/ss.h
index bff0846..bc816e7 100644
--- a/spectro/ss.h
+++ b/spectro/ss.h
@@ -44,6 +44,10 @@
#include "inst.h"
#include "ss_imp.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
#define SS_MAX_WR_SIZE 1000 /* Assumed maximum normal message query size */
#define SS_MAX_RD_SIZE 1000 /* Assumed maximum normal messagle answer size */
@@ -60,7 +64,7 @@ struct _ss {
inst_mode mode; /* Currently instrument mode */
/* Desired measurement configuration */
- ss_aft filt; /* Filter type (None/UV/D65 etc.) */
+ ss_aft filt; /* Filter type (None/UV/D65/Pol etc.) */
ss_dst dstd; /* Density standard (ANSI A/ANSI T/DIN etc.) */
ss_ilt illum; /* Illuminant type (A/C/D50 etc.) */
ss_ot obsv; /* Observer type (2deg/10deg) */
@@ -85,6 +89,9 @@ struct _ss {
int compen; /* Compensation filter enabled */
double comp[36]; /* Compensation filter */
+ xcalstd native_calstd; /* Instrument native calibration standard */
+ xcalstd target_calstd; /* Returned calibration standard */
+
#ifdef EMSST
int tmode; /* Transmission mode */
ss_rt sbr; /* Standby reference */
@@ -111,5 +118,9 @@ struct _ss {
/* Constructor */
extern ss *new_ss(icoms *icom, instType itype);
+#ifdef __cplusplus
+ }
+#endif
+
#define SS_H
#endif /* SS_H */
diff --git a/spectro/ss_imp.c b/spectro/ss_imp.c
index 6f184b3..05f0602 100644
--- a/spectro/ss_imp.c
+++ b/spectro/ss_imp.c
@@ -511,7 +511,7 @@ void ss_command(ss *p, double tmo) {
p->sbuf[2] = '\00'; /* write_read terminates on nul */
p->rbuf = p->_rbuf; /* Reset read pointer */
- if ((se = p->icom->write_read(p->icom, p->_sbuf, 0, p->_rbuf, SS_MAX_RD_SIZE, NULL, "\n", 1, tmo)) != 0) {
+ if ((se = p->icom->write_read_ex(p->icom, p->_sbuf, 0, p->_rbuf, SS_MAX_RD_SIZE, NULL, "\n", 1, tmo, 1)) != 0) {
p->snerr = icoms2ss_err(se);
return;
}
@@ -631,7 +631,7 @@ char pn[9], /* Return the part number */
unsigned int *sn, /* Return serial number */
char sv[13] /* Return software version */
) {
- char rsv[17]; /* Space for resered field */
+ char rsv[17]; /* Space for reserved field */
ss_add_soreq(p, ss_DeviceDataRequest);
ss_command(p, DF_TMO);
ss_sub_soans(p, ss_DeviceDataAnswer);
@@ -866,13 +866,13 @@ int ct /* Color temperature to set for illuminant Dxx in deg K/100 */
return ss_inst_err(p);
}
-/* Queries the spectra of the white reference for the desired filter */
+/* Queries the spectra of the white tile reference for the desired filter */
inst_code so_do_WhiteReferenceRequest(
ss *p,
ss_aft af, /* Filter being queried (None/Pol/D65/UV/custom */
ss_aft *raf, /* Return filter being queried (None/Pol/D65/UV/custom */
double sp[36], /* Return 36 spectral values */
-ss_owrt *owr, /* Return original white reference */
+ss_owrt *owr, /* Return original white reference (i.e. factory/user) */
char dtn[19] /* Return name of data table */
) {
int i;
@@ -890,6 +890,7 @@ char dtn[19] /* Return name of data table */
}
/* Load spectra of a user defined white reference for the desired filter. */
+/* This lets the user override the factory white tile calibration */
/* A name can be given to the white reference. */
inst_code so_do_WhiteReferenceDownld(
ss *p,
@@ -1312,12 +1313,20 @@ ss_toost oo /* Activated/Deactivated */
/* Initialise the device. Scans the Spectrolino */
/* (Doesn't work when device is offline ) */
inst_code ss_do_ScanInitializeDevice(ss *p) {
+ inst_code rv;
ss_add_ssreq(p, ss_InitializeDevice);
ss_command(p, IT_TMO);
ss_sub_ssans(p, ss_ErrorAnswer);
ss_incorp_scanerr(p, ss_sub_1(p));
chended(p);
- return ss_inst_err(p);
+ rv = ss_inst_err(p);
+
+ if (rv != inst_ok)
+ return rv;
+
+ /* Wait for Spectroscan to finish init. */
+ msec_sleep(3000);
+ return rv;
}
/* Establish communications between the SpectroScan and Spectrolino */
diff --git a/spectro/ss_imp.h b/spectro/ss_imp.h
index c298e80..ccd9ce3 100644
--- a/spectro/ss_imp.h
+++ b/spectro/ss_imp.h
@@ -37,6 +37,9 @@
and agreed to support.
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
/* Communication symbol definitions */
/* From the Gretag Spectrolino/Spectroscan */
@@ -1086,7 +1089,8 @@ ss_toost oo /* Activated/Deactivated */
/* Device Initialisation and configuration */
/* Initialise the device. Scans the Spectrolino */
-/* (Doesn't work when device is offline ) */
+/* (Doesn't work when device is offline, */
+/* takes some seconds for the device to recover after reply.) */
inst_code ss_do_ScanInitializeDevice(struct _ss *p);
/* Establish communications between the SpectroScan and Spectrolino */
@@ -1331,5 +1335,9 @@ struct _ss *p,
ss_sss *sss /* Return Special Status bits */
);
+#ifdef __cplusplus
+ }
+#endif
+
#define SS_IMP_H
#endif /* SS_IMP_H */
diff --git a/spectro/strange.cal b/spectro/strange.cal
index 5f2e94d..1e9451d 100644
--- a/spectro/strange.cal
+++ b/spectro/strange.cal
@@ -2,7 +2,7 @@ CAL
DESCRIPTOR "Argyll Device Calibration Curves"
ORIGINATOR "Argyll synthcal"
-CREATED "Mon Oct 26 01:10:48 2015"
+CREATED "Wed Sep 28 02:35:54 2016"
DEVICE_CLASS "DISPLAY"
COLOR_REP "RGB"
diff --git a/spectro/synthcal.c b/spectro/synthcal.c
index 75d18be..14471f6 100644
--- a/spectro/synthcal.c
+++ b/spectro/synthcal.c
@@ -41,6 +41,7 @@ usage(int level) {
fprintf(stderr,"Create a synthetic calibration file, Version %s\n",ARGYLL_VERSION_STR);
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
fprintf(stderr,"usage: synthcal [-options] outfile\n");
+ fprintf(stderr," -r res Set the calibration resolution (default 256)\n");
fprintf(stderr," -t N i = input, o = output, d = display (default)\n");
fprintf(stderr," -d col_comb choose colorant combination from the following (default 3):\n");
for (i = 0; ; i++) {
@@ -78,6 +79,7 @@ int main(int argc, char *argv[])
char *profDesc = NULL; /* Description */
int devtype = 2; /* debice type, 0 = in, 1 = out, 2 = display */
inkmask devmask = 0; /* ICX ink mask of device space */
+ int calres = 256; /* Resolution of resulting file */
int devchan; /* Number of chanels in device space */
char *ident; /* Ink combination identifier (includes possible leading 'i') */
char *bident; /* Base ink combination identifier */
@@ -120,8 +122,17 @@ int main(int argc, char *argv[])
else if (argv[fa][1] == 'v')
verb = 1;
+ /* Calibration file resolution */
+ else if (argv[fa][1] == 'r') {
+ fa = nfa;
+ if (na == NULL) usage(0);
+ calres = atoi(na);
+ if (calres < 2 || calres > MAX_CAL_ENT)
+ usage(0);
+ }
+
/* Select the device type */
- else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ else if (argv[fa][1] == 't') {
fa = nfa;
if (na == NULL) usage(0);
if (na[0] == 'i' || na[0] == 'I')
@@ -280,7 +291,7 @@ int main(int argc, char *argv[])
/* Write out the resulting calibration file */
{
- int i, j, calres = 256; /* 256 steps in calibration */
+ int i, j;
cgats *ocg; /* output cgats structure */
time_t clk = time(0);
struct tm *tsp = localtime(&clk);
diff --git a/spectro/usbio.c b/spectro/usbio.c
index 9f8964a..fca997d 100644
--- a/spectro/usbio.c
+++ b/spectro/usbio.c
@@ -90,7 +90,7 @@ static int icoms_usb_wait_io(
# ifdef NT
# include "usbio_nt.c"
# endif
-# if defined(__APPLE__)
+# if defined(UNIX_APPLE)
# include "usbio_ox.c"
# endif
# if defined(UNIX_X11)
@@ -491,7 +491,7 @@ double tout) /* Time out in seconds */
return ICOM_SYS;
}
- if (p->port_type(p) == icomt_usbserial)
+ if (p->dctype & icomt_fastserial)
fastserial = 1;
for (j = 0; j < bsize; j++)
@@ -517,7 +517,7 @@ double tout) /* Time out in seconds */
int c, rv;
int rsize = bsize;
- /* If not a fast USB serial port, read in quanta size chunks */
+ /* If not a fast USB/BT serial port, read in quanta size chunks */
if (!fastserial && rsize > p->rd_qa)
rsize = p->rd_qa;
@@ -614,8 +614,7 @@ char **pnames /* List of process names to try and kill before opening */
) {
a1logd(p->log, 8, "icoms_set_usb_port: About to set usb port characteristics\n");
- if (p->port_type(p) == icomt_usb
- || p->port_type(p) == icomt_usbserial) {
+ if (p->port_type(p) & icomt_usb) {
int rv;
if (p->is_open)
diff --git a/spectro/usbio.h b/spectro/usbio.h
index 578bd83..2a01ea3 100644
--- a/spectro/usbio.h
+++ b/spectro/usbio.h
@@ -44,7 +44,7 @@ struct usb_idevice {
# endif /* NT */
-# if defined(UNIX) && defined(__APPLE__)
+# if defined(UNIX_APPLE)
/* OS X structure version wrangling */
@@ -127,7 +127,7 @@ struct usb_idevice {
};
# endif /* OS X */
-# if defined(UNIX) && !defined(__APPLE__)
+# if defined(UNIX_X11)
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
diff --git a/spectro/usbio_bsd.c b/spectro/usbio_bsd.c
index 0af13a1..4b3e038 100644
--- a/spectro/usbio_bsd.c
+++ b/spectro/usbio_bsd.c
@@ -23,7 +23,7 @@
( Most of the below code is stubbed out, with the Linux
code as a placeholder. )
- BSD uses fd per end point, so simplifies things.
+ BSD uses fd per end point, so simplifies things (good).
No clear ep or abort i/o though, so we could try clear halt,
or close fd and see if that works in aborting transaction ?
@@ -57,7 +57,7 @@
#define poll_x poll
#endif
-/* Add paths to USB connected instruments */
+/* Add paths to USB connected device */
/* Return an icom error */
int usb_get_paths(
icompaths *p
@@ -75,7 +75,7 @@ icompaths *p
int vid, pid;
int nconfig = 0, nep = 0;
char *dpath;
- instType itype;
+ devType itype;
struct usb_idevice *usbd = NULL;
a1logd(p->log, 6, "usb_get_paths: about to look through usb devices:\n");
@@ -193,7 +193,7 @@ icompaths *p
break;
}
- a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
return ICOM_OK;
}
diff --git a/spectro/usbio_lx.c b/spectro/usbio_lx.c
index cb9ec59..6d001a2 100644
--- a/spectro/usbio_lx.c
+++ b/spectro/usbio_lx.c
@@ -81,7 +81,7 @@ char *dpath /* path to device */
unsigned char buf[IUSB_DESC_TYPE_DEVICE_SIZE];
unsigned vid, pid, nep10 = 0xffff;
unsigned int configix, nconfig, totlen;
- instType itype;
+ devType itype;
struct usb_idevice *usbd = NULL;
int fd; /* device file descriptor */
@@ -322,7 +322,7 @@ icompaths *p
}
}
- a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
return ICOM_OK;
}
@@ -384,6 +384,9 @@ void usb_close_port(icoms *p) {
ioctl(p->usbd->fd, USBDEVFS_RELEASEINTERFACE, &iface);
/* Workaround for some bugs - reset device on close */
+ /* !!!! Alternative would be to do reset before open.
+ On Linux the path stays the same, so could do open/reset/open
+ */
if (p->uflags & icomuf_reset_before_close) {
if ((rv = ioctl(p->usbd->fd, USBDEVFS_RESET, NULL)) != 0) {
a1logd(p->log, 1, "usb_close_port: reset returned %d\n",rv);
@@ -531,7 +534,8 @@ char **pnames /* List of process names to try and kill before opening */
/* Clear any errors. */
/* (Some I/F seem to hang if we do this, some seem to hang if we don't !) */
- /* The ColorMunki on Linux only starts every second time if we don't do this. */
+ /* (The ColorMunki on some Linux's only starts every second time if we don't do this, */
+ /* and on others, every second time if we do.) */
if (!(p->uflags & icomuf_no_open_clear)) {
for (i = 0; i < 32; i++) {
if (!p->ep[i].valid)
@@ -701,7 +705,8 @@ static void *urb_reaper(void *context) {
iurb = (usbio_urb *)out->usercontext;
req = iurb->req;
- a1logd(p->log, 8, "urb_reaper: urb reap URB %d with status %d bytes %d, urbs left %d\n",iurb->urbno, out->status, out->actual_length, req->nourbs-1);
+ a1logd(p->log, 8, "urb_reaper: urb reap URB %d with status %d, bytes %d, urbs left %d\n",iurb->urbno, out->status, out->actual_length, req->nourbs-1);
+
pthread_mutex_lock(&req->lock); /* Stop requester from missing reap */
req->nourbs--; /* We're reaped one */
@@ -778,7 +783,7 @@ static int icoms_usb_transaction(
int i;
in_usb_rw++;
- a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d\n",ttype,endpoint,length);
+ a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d to %d\n",ttype,endpoint,length, timeout);
if (!p->usbd->running) {
in_usb_rw--;
diff --git a/spectro/usbio_nt.c b/spectro/usbio_nt.c
index f5c3af8..34426fd 100644
--- a/spectro/usbio_nt.c
+++ b/spectro/usbio_nt.c
@@ -99,14 +99,14 @@ int *retsz) {
return ICOM_OK;
}
-/* Add paths to USB connected instruments */
+/* Add paths to USB connected device */
/* Return an icom error */
int usb_get_paths(
icompaths *p
) {
unsigned int vid, pid, nep10 = 0xffff;
unsigned int configix, nconfig, nifce;
- instType itype;
+ devType itype;
struct usb_idevice *usbd = NULL;
int rv, retsz, i;
diff --git a/spectro/usbio_ox.c b/spectro/usbio_ox.c
index d3da59a..2b09955 100644
--- a/spectro/usbio_ox.c
+++ b/spectro/usbio_ox.c
@@ -15,6 +15,8 @@
* see the License2.txt file for licencing details.
*/
+/* OS X I/O error codes are in IOKit/IOReturn.h */
+
#include <sys/time.h>
#include <CoreFoundation/CoreFoundation.h>
@@ -62,7 +64,7 @@ icompaths *p
CFNumberRef nconfref; /* No configurations */
CFNumberRef nepref, lidpref; /* No ep's, Location ID properties */
unsigned int vid = 0, pid = 0, nep, tnep, nconfig = 0, lid = 0;
- instType itype;
+ devType itype;
if ((ioob = IOIteratorNext(mit)) == 0)
break;
@@ -127,7 +129,7 @@ icompaths *p
unsigned int config = 0;
/* Get the configuration number */
- if ((nconfref = IORegistryEntryCreateCFProperty(ch1, CFSTR(kUSBNumEndpoints),
+ if ((nconfref = IORegistryEntryCreateCFProperty(ch1, CFSTR(kUSBConfigurationValue),
kCFAllocatorDefault,kNilOptions)) != 0) {
CFNumberGetValue(nconfref, kCFNumberIntType, &config);
CFRelease(nconfref);
@@ -157,16 +159,16 @@ icompaths *p
/* If this device is HID, it will have already added to the paths list, */
/* so check for this and skip this device if it is already there. */
- for (i = 0; i < p->npaths; i++) {
- if (p->paths[i]->vid == vid
- && p->paths[i]->pid == pid
- && p->paths[i]->hidd != NULL
- && p->paths[i]->hidd->lid == lid) {
+ for (i = 0; i < p->ndpaths[dtix_combined]; i++) {
+ if (p->dpaths[i][dtix_combined]->vid == vid
+ && p->dpaths[i][dtix_combined]->pid == pid
+ && p->dpaths[i][dtix_combined]->hidd != NULL
+ && p->dpaths[i][dtix_combined]->hidd->lid == lid) {
a1logd(p->log, 1, "usb_get_paths: Ignoring device because it is already in list as HID\n");
break;
}
}
- if (i < p->npaths) {
+ if (i < p->ndpaths[dtix_combined]) {
IOObjectRelease(ioob); /* Release found object */
free(usbd);
@@ -195,7 +197,7 @@ icompaths *p
}
IOObjectRelease(mit); /* Release the itterator */
- a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->ndpaths[dtix_combined]);
return ICOM_OK;
}
@@ -271,6 +273,8 @@ void usb_close_port(icoms *p) {
/* Workaround for some bugs - reset device on close */
if (p->uflags & icomuf_reset_before_close) {
IOReturn rv;
+ // ~~~~ may have to switch to ->USBDeviceReEnumerate(p->usbd->device, 0) ???
+ // because new OS X 10.11 ignore ResetDevice ?
if ((rv = (*(p->usbd->device))->ResetDevice(p->usbd->device)) != kIOReturnSuccess) {
a1logd(p->log, 1, "usb_close_port: ResetDevice failed with 0x%x\n",rv);
}
diff --git a/spectro/webwin.c b/spectro/webwin.c
index e13981a..1d5f713 100644
--- a/spectro/webwin.c
+++ b/spectro/webwin.c
@@ -70,7 +70,9 @@ char src_addr[20];
}
mg_printf(conn,
- "\r\n#%02X%02X%02X",
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n"
+ "#%02X%02X%02X",
(int)(p->r_rgb[0] * 255.0 + 0.5),
(int)(p->r_rgb[1] * 255.0 + 0.5),
(int)(p->r_rgb[2] * 255.0 + 0.5));
@@ -93,7 +95,8 @@ static void *webwin_ehandler(enum mg_event event,
} else if (strcmp(request_info->uri, "/webdisp.js") == 0) {
#ifndef NEVER
char *webdisp_js =
- "\r\n"
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: application/javascript\r\n\r\n"
"if (typeof XMLHttpRequest == \"undefined\") {\r\n"
" XMLHttpRequest = function () {\r\n"
" try { return new ActiveXObject(\"Msxml2.XMLHTTP.6.0\"); }\r\n"
@@ -141,17 +144,26 @@ static void *webwin_ehandler(enum mg_event event,
#else
return NULL; /* Read webdisp.js */
#endif
- } else {
+ } else if (strcmp(request_info->uri, "/") == 0) {
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Cache-Control: no-cache\r\n"
- "Content-Type: text/html\r\n\r\n"
+ "Content-Type: text/html; charset=UTF-8\r\n\r\n"
+ "<!DOCTYPE html>\r\n"
"<html>\r\n"
"<head>\r\n"
"<title>ArgyllCMS Web Display</title>\r\n"
"<script src=\"webdisp.js\"></script>\r\n"
"</head>\r\n"
+ "<body>\r\n"
+ "</body>\r\n"
"</html>\r\n"
);
+ } else {
+ mg_printf(conn, "HTTP/1.1 404 Not Found\r\n"
+ "Content-Type: text/plain\r\n\r\n"
+ "404 Not Found: %s",
+ request_info->uri
+ );
}
// "<script type=\"text/javascript\"src=\"webdisp.js\"></script>"
@@ -230,9 +242,9 @@ double r, double g, double b /* Color values 0.0 - 1.0 */
/* For video encoding the extra bits of precision are created by bit shifting */
/* rather than scaling, so we need to scale the fp value to account for this. */
- if (p->pdepth > 8)
- p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->pdepth - 8)))
- /((1 << p->pdepth) - 1.0);
+ if (p->edepth > 8)
+ p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->edepth - 8)))
+ /((1 << p->edepth) - 1.0);
}
}
@@ -361,8 +373,11 @@ int ddebug /* >0 to print debug statements to stderr */
p->ncix = 1;
- p->pdepth = 8; /* Assume this by API */
- p->edepth = 8;
+ p->fdepth = 8; /* Assume this by API */
+ p->rdepth = p->fdepth; /* Assumed */
+ p->ndepth = p->rdepth; /* Assumed */
+ p->nent = 0; /* No ramdac */
+ p->edepth = 8; /* Assumed */
/* Basic object is initialised, so create a web server */
diff --git a/spectro/xdg_bds.c b/spectro/xdg_bds.c
index c1805ed..e24e4ab 100644
--- a/spectro/xdg_bds.c
+++ b/spectro/xdg_bds.c
@@ -169,20 +169,22 @@ static char *append(char *in, char *app) {
return rv;
}
-/* Append a ':' or ';' then a string. Free in. Return NULL on error. */
+/* Append a ':' or ';' then a string. Free in. */
+/* Return NULL on error. */
static char *cappend(char *in, char *app) {
- int inlen;
+ int inlen, aplen;
char *rv;
inlen = strlen(in);
+ aplen = strlen(app);
- if ((rv = malloc(inlen + 1 + strlen(app) + 1)) == NULL) {
+ if ((rv = malloc(inlen + 1 + aplen + 1)) == NULL) {
a1loge(g_log, 1, "xdg_bds: cappend malloc failed\n");
free(in);
return NULL;
}
strcpy(rv, in);
- if (inlen > 1)
+ if (inlen > 0 && in[inlen-1] != SSEP && aplen > 0)
strcat(rv, SSEPS);
strcat(rv, app);
free(in);
@@ -190,20 +192,22 @@ static char *cappend(char *in, char *app) {
return rv;
}
-/* Append a '/' then a string. Free in. Return NULL on error. */
+/* Append a '/' then a string. Free in. */
+/* Return NULL on error. */
static char *dappend(char *in, char *app) {
- int inlen;
+ int inlen, aplen;
char *rv;
inlen = strlen(in);
+ aplen = strlen(app);
- if ((rv = malloc(inlen + 1 + strlen(app) + 1)) == NULL) {
+ if ((rv = malloc(inlen + 1 + aplen + 1)) == NULL) {
a1loge(g_log, 1, "xdg_bds: dappend malloc failed\n");
free(in);
return NULL;
}
strcpy(rv, in);
- if (inlen > 1 && in[inlen-1] != '/')
+ if (inlen > 0 && in[inlen-1] != '/')
strcat(rv, "/");
strcat(rv, app);
free(in);
@@ -332,7 +336,7 @@ int xdg_bds(
if (getenv("HOME") != NULL)
path = dappend(path, ".local/share");
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = dappend(path, "Library/Application Support");
#else /* Unix, Default */
path = dappend(path, ".local/share");
@@ -380,7 +384,7 @@ int xdg_bds(
if (getenv("HOME") != NULL)
path = dappend(path, ".config");
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = dappend(path, "Library/Preferences");
#else /* Unix, Default */
path = dappend(path, ".config");
@@ -435,7 +439,7 @@ int xdg_bds(
else
path = dappend(path, "Cache");
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = dappend(path, "Library/Caches");
#else /* Unix, Default */
path = dappend(path, ".cache");
@@ -477,7 +481,7 @@ int xdg_bds(
}
path = cappend(path, home);
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = cappend(path, "/Library");
#else
path = cappend(path, "/usr/local/share:/usr/share");
@@ -508,7 +512,7 @@ int xdg_bds(
}
path = cappend(path, home);
#else
-#ifdef __APPLE__
+#ifdef UNIX_APPLE
path = cappend(path, "/Library/Preferences");
#else
path = cappend(path, "/etc/xdg");
diff --git a/spectro/xdg_bds.h b/spectro/xdg_bds.h
index 5c29790..4fedbea 100644
--- a/spectro/xdg_bds.h
+++ b/spectro/xdg_bds.h
@@ -70,7 +70,7 @@ typedef enum {
#endif
/* ONLY use this for xdg_data type */
-#ifdef __APPLE__ /* fudge to assist OS X migration from */
+#ifdef UNIX_APPLE /* fudge to assist OS X migration from */
#define XDG_FUDGE SSEPS "../" /* Library/color to Library/Application Support/ArgyllCMS */
#else
#define XDG_FUDGE SSEPS
diff --git a/spectro/xrga.c b/spectro/xrga.c
new file mode 100644
index 0000000..0bf22fa
--- /dev/null
+++ b/spectro/xrga.c
@@ -0,0 +1,224 @@
+
+/*
+ * This file contains resources to translate colors to/from
+ * X-Rites XRGA calibration standard. This only applies to
+ * reflective measurements from historical Gretag-Macbeth & X-Rite
+ * instruments, and current X-Rite instruments.
+ */
+
+/*
+ * Author: Graeme W. Gill
+ * Date: 9/2/2016
+ * Version: 1.00
+ *
+ * Copyright 2016 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#if defined(UNIX)
+# include <utime.h>
+#else
+# include <sys/utime.h>
+#endif
+#include <sys/stat.h>
+#include <stdarg.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* !SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* !SALONEINSTLIB */
+#ifndef SALONEINSTLIB
+# include "plot.h"
+#endif
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "inst.h"
+#include "rspec.h"
+
+#include "xrga.h"
+
+/* A conversion equation */
+typedef struct {
+ double gain0, gain1; /* Destination gain at 550 nm, slope */
+ double wl0; /* Wavlength shift at 550nm to source - assumed constant */
+} xrga_eqn;
+
+/* XRGA conversion values in order [pol][src][dst] */
+/* Parameters are gain at 550nm, slope of gain per nm, src wavelengh offset in nm. */
+/* These values were inferred from the results one gets from processing spectral */
+/* values though X-Rite's conversion routines. */
+
+xrga_eqn xrga_equations[2][3][3] = {
+ { /* Unpolarized */
+ {
+ { 1.000000, 0.000000, 0.000000 }, /* XRDI -> XRDI */
+ { 1.000046, -0.000050, -1.400568 }, /* XRDI -> GMDI */
+ { 1.000005, -0.000025, -0.400084 } /* XRDI -> XRGA */
+ },
+ {
+ { 1.000046, 0.000050, 1.400568 }, /* GMDI -> XRDI */
+ { 1.000000, 0.000000, 0.000000 }, /* GMDI -> GMDI */
+ { 1.000015, 0.000025, 1.000207 } /* GMDI -> XRGA */
+ },
+ {
+ { 1.000005, 0.000025, 0.400084 }, /* XRGA -> XRDI */
+ { 1.000015, -0.000025, -1.000207 }, /* XRGA -> GMDI */
+ { 1.000000, 0.000000, 0.000000 } /* XRGA -> XRGA */
+ }
+ },
+ { /* Polarized */
+ {
+ { 1.000000, 0.000000, 0.000000 }, /* XRDI -> XRDI */
+ { 1.028710, -0.000081, -1.399477 }, /* XRDI -> GMDI */
+ { 1.000005, -0.000025, -0.400084 } /* XRDI -> XRGA */
+ },
+ {
+ { 0.971957, 0.000072, 1.398829 }, /* GMDI -> XRDI */
+ { 1.000000, 0.000000, 0.000000 }, /* GMDI -> GMDI */
+ { 0.971975, 0.000049, 0.998938 } /* GMDI -> XRGA */
+ },
+ {
+ { 1.000005, 0.000025, 0.400084 }, /* XRGA -> XRDI */
+ { 1.028711, -0.000056, -0.999421 }, /* XRGA -> GMDI */
+ { 1.000000, 0.000000, 0.000000 } /* XRGA -> XRGA */
+ }
+ }
+};
+
+
+/* Core conversion code. dst and src are assumed to be different xspect's */
+static void convert_xrga(xspect *dst, xspect *src, xrga_eqn *eq) {
+ int j;
+
+ XSPECT_COPY_INFO(dst, src); /* Copy parameters */
+
+ for (j = 0; j < dst->spec_n; j++) {
+ double dw, sw, ga;
+ double spcing, f;
+ double y[4], yw;
+ double x[4];
+ int i;
+
+ dw = XSPECT_XWL(dst, j); /* Destination wavelength */
+ sw = dw + eq->wl0; /* Source wavelength */
+ ga = eq->gain0 + (dw - 550.0) * eq->gain1; /* Gain at this dest wl */
+
+ /* Compute fraction 0.0 - 1.0 out of known spectrum. */
+ /* Place it so that the target wavelength lands in middle section */
+ /* of Lagrange basis points. */
+ spcing = (src->spec_wl_long - src->spec_wl_short)/(src->spec_n-1.0);
+ f = (sw - src->spec_wl_short) / (src->spec_wl_long - src->spec_wl_short);
+ f *= (src->spec_n - 1.0);
+ i = (int)floor(f); /* Base grid coordinate */
+
+ if (i < 1) /* Limit to valid Lagrange basis index range, */
+ i = 1; /* and extrapolate from that at the ends. */
+ else if (i > (src->spec_n - 3))
+ i = (src->spec_n - 3);
+
+ /* Setup the surrounding values */
+ x[0] = src->spec_wl_short + (i-1) * spcing;
+ y[0] = src->spec[i-1];
+ x[1] = src->spec_wl_short + i * spcing;
+ y[1] = src->spec[i];
+ x[2] = src->spec_wl_short + (i+1) * spcing;
+ y[2] = src->spec[i+1];
+ x[3] = src->spec_wl_short + (i+2) * spcing;
+ y[3] = src->spec[i+2];
+
+
+ /* Compute interpolated value using Lagrange: */
+ yw = y[0] * (sw-x[1]) * (sw-x[2]) * (sw-x[3])/((x[0]-x[1]) * (x[0]-x[2]) * (x[0]-x[3]))
+ + y[1] * (sw-x[0]) * (sw-x[2]) * (sw-x[3])/((x[1]-x[0]) * (x[1]-x[2]) * (x[1]-x[3]))
+ + y[2] * (sw-x[0]) * (sw-x[1]) * (sw-x[3])/((x[2]-x[0]) * (x[2]-x[1]) * (x[2]-x[3]))
+ + y[3] * (sw-x[0]) * (sw-x[1]) * (sw-x[2])/((x[3]-x[0]) * (x[3]-x[1]) * (x[3]-x[2]));
+
+ yw *= ga;
+
+ dst->spec[j] = yw;
+ }
+}
+
+/* Apply a conversion from one calibration standard to another to an xspect */
+void xspec_convert_xrga(xspect *dst, xspect *srcp, xcalpol pol, xcalstd dsp, xcalstd ssp) {
+ xrga_eqn *eq;
+ xspect tmp, *src = srcp;
+
+ /* If no conversion and no copy needed */
+ if ((ssp == xcalstd_native || dsp == xcalstd_native || dsp == ssp)
+ && dst == src)
+ return;
+
+ /* If no conversion needed */
+ if (ssp == xcalstd_native || dsp == xcalstd_native || dsp == ssp) {
+ *dst = *src; /* Struct copy */
+ return;
+ }
+
+ /* If the dest is the same as the src, make a temporary copy */
+ if (dst == src) {
+ tmp = *src; /* Struct copy */
+ src = &tmp;
+
+ } else {
+ XSPECT_COPY_INFO(dst, src); /* Copy parameters */
+ }
+
+ eq = &xrga_equations[pol][ssp][dsp];
+ convert_xrga(dst, src, eq);
+}
+
+/* Apply a conversion from one calibration standard to another to an array of ipatch's */
+void ipatch_convert_xrga(ipatch *vals, int nvals,
+ xcalpol pol, xcalstd dsp, xcalstd ssp, int clamp) {
+ xrga_eqn *eq;
+ xspect tmp;
+ xsp2cie *conv = NULL; /* Spectral to XYZ conversion object */
+ int i;
+
+ /* If no conversion needed */
+ if (ssp == xcalstd_native || dsp == xcalstd_native
+ || dsp == ssp || nvals <= 0)
+ return;
+
+ /* Conversion to use */
+ eq = &xrga_equations[pol][ssp][dsp];
+
+ for (i = 0; i < nvals; i++) {
+ if (vals[i].mtype != inst_mrt_reflective
+ || vals[i].sp.spec_n <= 0) {
+ continue;
+ }
+ tmp = vals[i].sp; // Struct copy */
+ convert_xrga(&vals[i].sp, &tmp, eq);
+
+ /* Re-compute XYZ */
+ if (vals[i].XYZ_v) {
+ if (conv == NULL) {
+ conv = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2,
+ NULL, icSigXYZData, (icxClamping)clamp);
+ }
+ conv->convert(conv, vals[i].XYZ, &vals[i].sp);
+ vals[i].XYZ_v = 1;
+ vals[i].XYZ[0] *= 100.0; /* Convert to % */
+ vals[i].XYZ[1] *= 100.0;
+ vals[i].XYZ[2] *= 100.0;
+ }
+ }
+ if (conv != NULL)
+ conv->del(conv);
+}
diff --git a/spectro/xrga.h b/spectro/xrga.h
new file mode 100644
index 0000000..0605fc8
--- /dev/null
+++ b/spectro/xrga.h
@@ -0,0 +1,86 @@
+
+#ifndef XRGA_H
+#define XRGA_H
+
+/*
+ * This file contains resources to translate colors to/from
+ * X-Rites XRGA calibration standard. This only applies to
+ * reflective measurements from historical Gretag-Macbeth & X-Rite
+ * instruments, and current X-Rite instruments.
+ */
+
+/*
+ * Author: Graeme W. Gill
+ * Date: 9/2/2016
+ * Version: 1.00
+ *
+ * Copyright 2016 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef enum {
+ xcalstd_nonpol = 0, /* Unpolarized */
+ xcalstd_pol = 1 /* Polarized */
+} xcalpol;
+
+/* Apply a conversion from one calibration standard to another to an xspect. */
+void xspec_convert_xrga(xspect *dst, xspect *srcp, xcalpol pol, xcalstd dsp, xcalstd ssp);
+
+/* Apply a conversion from one calibration standard to another to an array of ipatch's */
+void ipatch_convert_xrga(ipatch *vals, int nvals,
+ xcalpol pol, xcalstd dsp, xcalstd ssp, int clamp);
+
+/* Macro returns true if a conversion is needed */
+#define XCALSTD_NEEDED(ssp, dsp) \
+ ((ssp) != xcalstd_native && (dsp) != xcalstd_native && (dsp) != (ssp))
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* XRGA_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/target/alphix.c b/target/alphix.c
index 68dfd48..6e5fc85 100644
--- a/target/alphix.c
+++ b/target/alphix.c
@@ -1,8 +1,10 @@
/*
- * Argyll Color Correction System
- *
* Alphabetic index class.
+ */
+
+/*
+ * Argyll Color Correction System
*
* Author: Graeme W. Gill
* Date: 22/8/2005
@@ -63,6 +65,10 @@ static int fromanat(alphix *p, char *ax) {
int cl;
int i, k, rv = 0;
+ cl = strlen(ax);
+ if (cl > p->nd) /* String is too long to be our index */
+ return -1;
+
if (p->nd > 10) {
if ((tb = malloc((p->nd+1) * sizeof(char))) == NULL)
return -1; /* Malloc error */
@@ -70,7 +76,6 @@ static int fromanat(alphix *p, char *ax) {
tb = _tb;
/* Pack the string out to the right number of digits with spaces. */
- cl = strlen(ax);
for (v = tb; cl < p->nd; v++, cl++)
*v = ' ';
strcpy(v, ax);
@@ -110,7 +115,7 @@ static char *find_start(alphix *p, char *ax) {
if (*v == p->ds[i].seq[k])
break; /* Found */
}
- if (k >= p->ds[i].n) /* Not found */
+ if (k >= p->ds[i].n) /* Not found, so we are at the start */
break;
}
return v+1;
@@ -444,6 +449,9 @@ int patch_location_order(
/* We assume that the sequences are distinguishable ... */
v = find_start(rh, ax);
+ if (*v == '\000') /* Nothing looks like a alphix */
+ return -1;
+
ri = rh->nix(rh, v);
*v = '\000';
li = lh->nix(lh, ax);
diff --git a/target/alphix.h b/target/alphix.h
index 091c191..aad5b9f 100644
--- a/target/alphix.h
+++ b/target/alphix.h
@@ -2,9 +2,11 @@
#ifndef ALPHIX_H
/*
- * Argyll Color Correction System
- *
* Alphabetic indexing class
+ */
+
+/*
+ * Argyll Color Correction System
*
* Author: Graeme W. Gill
* Date: 22/8/2005
diff --git a/target/ofps.c b/target/ofps.c
index dfcee2e..5c2219c 100644
--- a/target/ofps.c
+++ b/target/ofps.c
@@ -66,7 +66,7 @@
dimension points are aware of the lower dimension
ones. In this way the distribution of points on
lower dimensional surfaces is well spread, while
- the higher dimension points take thier positions into account.
+ the higher dimension points take their positions into account.
*/
/*
@@ -107,7 +107,7 @@
In general there are many sub-dimensions views, not all of
which would probably be regarded as important.
- To measure spread, independent voronoi tesselations of
+ To measure spread, independent voronoi tessellations of
these sub dimensions would be neededi, and they could be
used partly driver optimization (??).
@@ -717,6 +717,85 @@ default_ofps_to_percept(void *od, double *p, double *d) {
}
}
+/* Filtered perceptual lookup, used for setting up rspl cache values. */
+/* Input is device values, output L*a*b* like perceptual values. */
+static void
+filtered_ofps_to_percept(void *ss, double *p, double *d) {
+ ofps *s = (ofps *)ss;
+ double rad = 1.0/s->pcache_res; /* Filter radius = grid res. */
+ int fres = 2; /* +/- 2 around center */
+ int e, f;
+ double pw; /* Accumulated Weight */
+ double off[MXPD]; /* Offset value */
+ double out[MXPD]; /* Offset output value */
+ double roff[MXPD]; /* Reflection offset value (for clip case) */
+ double rout[MXPD]; /* Reflected offset output value */
+ DCOUNT(co, MXPD, s->di, -fres, -fres, fres+1);
+
+ if (rad > 0.05) /* Don't loose too much detail */
+ rad = 0.05;
+
+//printf("filtered called with %s\n",debPdv(s->di,d));
+
+ for (f = 0; f < s->di; f++)
+ p[f] = 0.0; /* Accumulated value */
+ pw = 0.0;
+
+ DC_INIT(co);
+
+ while (!DC_DONE(co)) {
+ double tw = 1.0;
+ int clip = 0;
+
+//printf(" sub samp at %s\n", debPiv(s->di, co));
+ for (e = 0; e < s->di; e++) {
+ double w, ov;
+ ov = ((double)co[e])/(fres+1) * rad;
+ roff[e] = off[e] = d[e] + ov;
+ if (off[e] < 0.0) {
+ off[e] = 0.0;
+ roff[e] = 0.0 - ov;
+ clip = 1;
+ }
+ else if (off[e] > 1.0) {
+ off[e] = 1.0;
+ roff[e] = 1.0 - ov;
+ clip = 1;
+ }
+//printf(" w[%d] = %f\n",e,(fres+1 - fabs((double)co[e]))/(fres+1));
+ w = (fres+1 - fabs((double)co[e]))/(fres+1);
+ tw *= w;
+ }
+//printf(" off %s wt %f\n", debPdv(s->di,off),tw);
+ s->percept(s->od, out, off);
+
+ /* For clipped case, use reflected value from reflected location */
+ if (clip) {
+ s->percept(s->od, rout, roff);
+//printf(" roff %s\n", debPdv(s->di, roff));
+//printf(" out %s\n", debPdv(s->di, out));
+//printf(" rout %s\n", debPdv(s->di, rout));
+
+ for (f = 0; f < s->di; f++)
+ out[f] = 2 * out[f] - rout[f];
+
+//printf(" eout %s\n", debPdv(s->di, out));
+ }
+ for (f = 0; f < s->di; f++)
+ p[f] += tw * out[f];
+ pw += tw;
+
+ DC_INC(co);
+ }
+ for (f = 0; f < s->di; f++)
+ p[f] /= pw;
+
+//s->percept(s->od, out, d);
+//printf(" u out %s\n", debPdv(s->di, out));
+//printf(" f out %s\n", debPdv(s->di, p));
+//printf("\n");
+}
+
/* Cached perceptual lookup */
static void
ofps_cache_percept(void *od, double *p, double *d) {
@@ -4968,27 +5047,41 @@ ofps_init_pcache(ofps *s) {
if (gr > TNPAGRIDMAXRES)
gr = TNPAGRIDMAXRES;
+#ifndef DEBUG
if (s->verb)
- printf("Perceptual cache resolution = %d\n",gr);
-
-#ifdef DEBUG
- printf("Perceptual cache resolution = %d\n",gr);
#endif
+ {
+ printf("Perceptual cache resolution = %d\n",gr);
+ printf("Seeding cache..."); fflush(stdout);
+ }
/* Create a rspl to cache the perceptual lookup */
-
if ((s->pcache = new_rspl(RSPL_NOFLAGS, s->di, s->di)) == NULL)
error("new_rspl failed");
for (e = 0; e < di; e++)
gres[e] = gr;
+ s->pcache_res = gr;
- s->pcache->set_rspl(s->pcache, RSPL_SET_APXLS, s->od, s->percept, NULL, NULL, gres, NULL, NULL);
+// s->pcache->set_rspl(s->pcache, RSPL_SET_APXLS, s->od, s->percept, NULL, NULL, gres, NULL, NULL);
+
+ /* Filtering seems to make this more robust for some profiles, less for others. */
+ if (s->percept != default_ofps_to_percept)
+ s->pcache->set_rspl(s->pcache, RSPL_NOFLAGS, s, filtered_ofps_to_percept,
+ NULL, NULL, gres, NULL, NULL);
+ else
+ s->pcache->set_rspl(s->pcache, RSPL_NOFLAGS, s->od, s->percept,
+ NULL, NULL, gres, NULL, NULL);
/* Hmm. Should we store the underlying ->percept & ->od somewhere before we overwrite it ? */
s->percept = ofps_cache_percept;
s->od = s->pcache;
+#ifndef DEBUG
+ if (s->verb)
+#endif
+ printf("done\n");
+
}
/* --------------------------------------------------- */
diff --git a/target/ofps.h b/target/ofps.h
index e2b1d55..05ca121 100644
--- a/target/ofps.h
+++ b/target/ofps.h
@@ -276,10 +276,12 @@ struct _ofps {
unsigned int lwmask; /* Last word mask */
/* Perceptual function handed in. All device values must have been */
- /* clipped before calling this, otherwise use It is assumed that */
+ /* clipped before calling this. (On running, is replaced with rspl */
+ /* cached version) */
void (*percept)(void *od, double *out, double *in);
void *od; /* Opaque data for perceptual point */
+ int pcache_res; /* Grid resolution of pcache */
rspl *pcache; /* cache of perceptual lookup */
/* Other info */
diff --git a/target/targen.c b/target/targen.c
index a29ef63..74bbe96 100644
--- a/target/targen.c
+++ b/target/targen.c
@@ -43,8 +43,10 @@
/* NOTE:
- The device model is assumed to not take xpow into account,
- hence the expected values don't reflect its effect.
+ xpow is applied over the top of the normal or supplied
+ device model, so it effectively becomes a modification
+ of the device model.
+
The general filter is applied prior to the xpow being applied.
Many of the test patch types do take it into account
when computing the ink limit.
@@ -101,6 +103,10 @@
any possible angle, none of the test data points should appear
to line up. The Argyll target generator seems to acheive this goal.
+ A final problem withe regular grids is that they can lead to
+ Runge's phenomenon, depending on the nature of the interpolation
+ algorithm used.
+
*/
#undef DEBUG
@@ -677,7 +683,7 @@ double xpow /* Extra device power, default = none */
if (xpow < 0.0)
xpow = XPOW_DEFAULT;
- s->ixpow = xpow;
+ s->ixpow = 1.0/xpow;
/* See if we have a profile */
if (profName != NULL
@@ -877,6 +883,7 @@ usage(int level, char *diag, ...) {
fprintf(stderr," -V demphasis Degree of dark region patch concentration 1.0-4.0 (default %.2f = none)\n",DEMPH_DEFAULT);
fprintf(stderr," -F L,a,b,rad Filter out samples outside Lab sphere.\n");
fprintf(stderr," -O Don't re-order display RGB patches for minimum delay\n");
+ fprintf(stderr," -U Don't filter out duplicate patches\n");
#ifdef VRML_DIAG
fprintf(stderr," -w Dump diagnostic outfilel%s file (Lab locations)\n",vrml_ext());
fprintf(stderr," -W Dump diagnostic outfiled%s file (Device locations)\n",vrml_ext());
@@ -941,8 +948,9 @@ int main(int argc, char *argv[]) {
double uilimit = -1.0; /* Underlying (pre-calibration, scale 1.0) ink limit */
double nemph = NEMPH_DEFAULT;
double demph = DEMPH_DEFAULT;
+ int dontdedupe = 0; /* Don't filter duplicate samples */
int dontreorder = 0; /* Don't re-order RGB display patches for min delay */
- int filter = 0; /* Filter values */
+ int filter = 0; /* Filter values outside given sphere */
double filt[4] = { 50,0,0,0 };
static char fname[MAXNAMEL+1] = { 0 }; /* Output file base name */
static char pname[MAXNAMEL+1] = { 0 }; /* Device profile name */
@@ -1231,6 +1239,11 @@ int main(int argc, char *argv[]) {
dontreorder = 1;
}
+ /* Don't filter out redundant patches */
+ else if (argv[fa][1] == 'U') {
+ dontdedupe = 1;
+ }
+
#ifdef VRML_DIAG
else if (argv[fa][1] == 'w') /* Lab */
dumpvrml |= 1;
@@ -1612,7 +1625,7 @@ int main(int argc, char *argv[]) {
val[e] = icx_powlike(val[e], xpow * demph);
/* See if it is already in the fixed list */
- if (fxlist != NULL) {
+ if (!dontdedupe && fxlist != NULL) {
int k;
for (k = 0; k < fxno; k++) {
for (e = 0; e < di; e++) {
@@ -1717,7 +1730,7 @@ int main(int argc, char *argv[]) {
addp = 0;
/* See if it is already in the fixed list */
- if (fxlist != NULL) {
+ if (!dontdedupe && fxlist != NULL) {
int k;
for (k = 0; k < fxno; k++) {
for (e = 0; e < di; e++) {
@@ -1802,7 +1815,7 @@ int main(int argc, char *argv[]) {
addp = 0; /* Don't add patches over ink limit */
/* See if it is already in the fixed list */
- if (addp && fxlist != NULL) {
+ if (addp && !dontdedupe && fxlist != NULL) {
int k;
for (k = 0; k < fxno; k++) {
for (e = 0; e < di; e++) {
@@ -1891,7 +1904,7 @@ int main(int argc, char *argv[]) {
addp = 1; /* Default add the point */
/* See if it is already in the fixed list */
- if (fxlist != NULL) {
+ if (!dontdedupe && fxlist != NULL) {
int k;
for (k = 0; k < fxno; k++) {
for (e = 0; e < di; e++) {
@@ -1998,7 +2011,7 @@ int main(int argc, char *argv[]) {
addp = 0; /* Don't add patches over ink limit */
/* See if it is already in the fixed list */
- if (addp && fxlist != NULL) {
+ if (addp && !dontdedupe && fxlist != NULL) {
int k;
for (k = 0; k < fxno; k++) {
for (e = 0; e < di; e++) {
diff --git a/ttbd.txt b/ttbd.txt
index 0a6ac0b..e1af581 100644
--- a/ttbd.txt
+++ b/ttbd.txt
@@ -1,6 +1,15 @@
Argyll - Things To Be Done & odeas (in no particular priority)
--------------------------
+Next release:
+
+ Fix LUT loading to have +/- 1 margine
+
+ Add new JETI instrument support
+
+
+--------------------
+
Categories:
1) Ideas list
diff --git a/tweak/refine.c b/tweak/refine.c
index 6e06882..4bcdfbb 100644
--- a/tweak/refine.c
+++ b/tweak/refine.c
@@ -78,7 +78,6 @@
#include "numlib.h"
#include "rspl.h"
#include "xicc.h"
-#include "xicc.h"
#include "ui.h"
#define COMPLOOKUP /* Compound with previous in ICM lookup rather than rspl */
@@ -388,10 +387,20 @@ main(int argc, char *argv[]) {
spec = 1;
tillum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
spec = 1;
tillum = icxIT_custom;
- if (read_xspect(&cust_tillum, na) != 0)
- usage("Unable to read custom spectrum '%s'",na);
+ if (read_xspect(&cust_tillum, &mt, na) != 0)
+ usage("Unable to read target spectrum '%s'",na);
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("Target illuminant '%s' is wrong measurement type",na);
+ }
}
}
}
@@ -425,10 +434,20 @@ main(int argc, char *argv[]) {
spec = 1;
illum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
spec = 1;
illum = icxIT_custom;
- if (read_xspect(&cust_illum, na) != 0)
+ if (read_xspect(&cust_illum, &mt, na) != 0)
usage("Unable to read custom spectrum '%s'",na);
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("CIE illuminant '%s' is wrong measurement type",na);
+ }
}
}
diff --git a/usb/55-Argyll.rules b/usb/55-Argyll.rules
index 704e7cf..703d139 100644
--- a/usb/55-Argyll.rules
+++ b/usb/55-Argyll.rules
@@ -5,6 +5,27 @@
# and remove /usr/lib/udev/rules.d/69-cd-sensors.rules
# as appropriate for your system
+#--------------------------------------------------------------------------
+# Copyright 2012 Graeme W. Gill.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this file, to deal in this file without restriction, including without
+# limitation the rights to use, copy, modify, merge, publish, distribute,
+# sublicense, and/or sell copies of this file, and to permit persons to whom
+# this file is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of this file.
+#
+# THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
+# THIS FILE.
+#--------------------------------------------------------------------------
+
# Skip all this to speed things up if it'a not a usb add.
ACTION!="add", GOTO="argyll_rules_end"
SUBSYSTEM!="usb", GOTO="argyll_rules_end"
@@ -102,22 +123,26 @@ ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1002", ENV{COLORD_SENSOR_KIND}="colo
ATTRS{idVendor}=="2457", ATTRS{idProduct}=="4000", ENV{COLORD_SENSOR_KIND}="ex1", ENV{COLORD_SENSOR_CAPS}="lcd crt ambient"
#########################################################
-# color calibration device
-ENV{COLORD_SENSOR_KIND}=="*?", ENV{COLOR_MEASUREMENT_DEVICE}="1"
# Set ID_VENDOR and ID_MODEL acording to VID and PID
#TEST=="/lib/udev/usb-db", IMPORT{program}="usb-db %p"
ENV{COLORD_SENSOR_KIND}=="*?", ENV{ID_MODEL}=="", IMPORT{program}="usb_id --export %p"
ENV{COLORD_SENSOR_KIND}=="*?", ENV{ID_MODEL_FROM_DATABASE}=="", IMPORT{program}="usb-db %p"
-# Debian has
-# ...., TAG+="uaccess", TAG+="udev-acl" # Debian, but should be in 70-uaccess.rules
+# Is a color calibration device. 70-uaccess.rules may use this to set TAG+="uaccess",
+# but there is no way to know if this is the case from here.
+# May also be used by other rules to avoid claiming this device.
+ENV{COLORD_SENSOR_KIND}=="*?", ENV{COLOR_MEASUREMENT_DEVICE}="1"
-# Let udev-acl manage these devices, if it's available
-TEST=="/var/run/ConsoleKit/database", ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}="1"
+# Let ConsoleKit udev-acl manage these devices, if it's available.
+# (Except that this stuffs up on Slackware 14.1 because
+# ConsoleKit/database is present even when ACL is not enabled).
+# Some recent systems no longer use ConsoleKit or ACL_MANAGE - acl is done by systemd ?
+# TEST=="/var/run/ConsoleKit/database", ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}="1"
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}="1"
-# Otherwise, restrict access to members of the colord group,
-# which the user may have to add to the system and add themselves to.
-ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}!="*?", MODE="660", GROUP="colord"
+# In any case, make color instruments accessible to members of the colord group,
+# which the user may have to add to the system and add themselves to if ACL isn't present.
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", MODE="660", GROUP="colord"
LABEL="argyll_rules_end"
diff --git a/usb/ArgyllCMS.cat b/usb/ArgyllCMS.cat
index 2b713c9..cd06c92 100644
--- a/usb/ArgyllCMS.cat
+++ b/usb/ArgyllCMS.cat
Binary files differ
diff --git a/usb/ArgyllCMS.inf b/usb/ArgyllCMS.inf
index db0995f..4de9f51 100644
--- a/usb/ArgyllCMS.inf
+++ b/usb/ArgyllCMS.inf
@@ -1,229 +1,229 @@
-;--------------------------------------------------------------------------
-; Copyright 2012 Graeme W. Gill.
-;
-; Permission is hereby granted, free of charge, to any person obtaining a copy
-; of this file, to deal
-; in this file without restriction, including without limitation the rights
-; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-; copies of this file, and to permit persons to whom this file is
-; furnished to do so, subject to the following conditions:
-;
-; The above copyright notice and this permission notice shall be included in
-; all copies or substantial portions of this file.
-;
-; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
-; THIS FILE.
-;--------------------------------------------------------------------------
-
-; ==== Strings ====
-
-[Strings]
-
-DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
-
-Date = "01/17/2012" ; MM/DD/YYYY
-libusb0ver = "1.2.6.0"
-
-Libusb_ClassName = "Argyll LibUSB-win32 devices"
-Libusb_DiskName = "LibUSB-win32 Device Install Disk"
-
-libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
-
-; ==== Version ====
-
-[Version]
-Signature = "$Windows NT$"
-DriverVer = %Date%,%libusb0ver%
-Provider = "ArgyllCMS"
-
-; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
-Class = %Libusb_ClassName%
-ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
-CatalogFile = "ArgyllCMS.cat"
-CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
-
-[ClassInstall32]
-AddReg=class_install_add_reg
-
-[class_install_add_reg]
-HKR,,,,%Libusb_ClassName%
-HKR,,Icon,,"-20" ; -20 is for the USB icon
-
-; ==== Files Sources and Destinations ====
-
-[SourceDisksNames]
-1 = %Libusb_DiskName%
-
-[SourceDisksFiles]
-libusb0.sys = 1,\bin\x86,
-
-[SourceDisksFiles.amd64]
-libusb0.sys = 1,\bin\amd64,
-
-[DestinationDirs]
-libusb0_files_sys = 10,system32\drivers
-
-; ==== libusb0 Device driver ====
-
-[libusb0_files_sys]
-libusb0.sys,libusb0.sys
-
-; For each one of these, there must be one for Services !!!
-[LIBUSB0_DEV]
-CopyFiles = Libusb0_files_sys
-
-[LIBUSB0_DEV.HW]
-AddReg = libusb0_add_reg_hw
-
-[libusb0_add_reg]
-HKR,,DevLoader,,*ntkern
-HKR,,NTMPDriver,,libusb0.sys
-
-[libusb0_add_reg_hw]
-HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
-HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
-
-[LIBUSB0_DEV.Services]
-AddService = libusb0, 0x00000002, libusb0_add_service
-
-[libusb0_add_service]
-DisplayName = %libusb0_SvcDesc%
-ServiceType = 1
-StartType = 3
-ErrorControl = 0
-ServiceBinary = %12%\libusb0.sys
-
-; ==== Manufacturers ====
-
-[Manufacturer]
-"HCFR Association"=HCFR_Devices,NTx86,NTamd64
-"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
-"X-Rite"=X_Rite_Devices,NTx86,NTamd64
-"ColorVision"=ColorVision_Devices,NTx86,NTamd64
-"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
-"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
-"Image Engineering"=ImageEngineering_Devices,NTx86,NTamd64
-
-; ==== Devices ====
-
-[HCFR_Devices]
-"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
-"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
-
-[Sequel_Devices]
-"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
-
-[X_Rite_Devices]
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
-"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
-"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
-"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
-"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
-"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
-
-[ColorVision_Devices]
-"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
-"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
-"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
-"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
-"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
-
-[GM_X_Rite_Devices]
-"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
-"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
-"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
-"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
-"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
-
-[Hughski_Devices]
-"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
-
-[ImageEngineering_Devices]
-"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
-
-
-[HCFR_Devices.NTx86]
-"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
-"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
-
-[Sequel_Devices.NTx86]
-"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
-
-[X_Rite_Devices.NTx86]
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
-"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
-"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
-"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
-"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
-"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
-
-[ColorVision_Devices.NTx86]
-"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
-"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
-"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
-"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
-"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
-
-[GM_X_Rite_Devices.NTx86]
-"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
-"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
-"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
-"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
-"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
-
-[Hughski_Devices.NTx86]
-"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
-
-[ImageEngineering_Devices.NTx86]
-"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
-
-
-[HCFR_Devices.NTamd64]
-"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
-"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
-
-[Sequel_Devices.NTamd64]
-"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
-
-[X_Rite_Devices.NTamd64]
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
-"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
-"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
-"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
-"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
-"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
-
-[ColorVision_Devices.NTamd64]
-"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
-"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
-"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
-"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
-"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
-
-[GM_X_Rite_Devices.NTamd64]
-"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
-"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
-"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
-"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
-"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
-
-[Hughski_Devices.NTamd64]
-"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
-
-[ImageEngineering_Devices.NTamd64]
-"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
-
+;--------------------------------------------------------------------------
+; Copyright 2012 Graeme W. Gill.
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this file, to deal
+; in this file without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of this file, and to permit persons to whom this file is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of this file.
+;
+; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
+; THIS FILE.
+;--------------------------------------------------------------------------
+
+; ==== Strings ====
+
+[Strings]
+
+DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
+
+Date = "01/17/2012" ; MM/DD/YYYY
+libusb0ver = "1.2.6.0"
+
+Libusb_ClassName = "Argyll LibUSB-win32 devices"
+Libusb_DiskName = "LibUSB-win32 Device Install Disk"
+
+libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
+
+; ==== Version ====
+
+[Version]
+Signature = "$Windows NT$"
+DriverVer = %Date%,%libusb0ver%
+Provider = "ArgyllCMS"
+
+; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
+Class = %Libusb_ClassName%
+ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
+CatalogFile = "ArgyllCMS.cat"
+CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
+
+[ClassInstall32]
+AddReg=class_install_add_reg
+
+[class_install_add_reg]
+HKR,,,,%Libusb_ClassName%
+HKR,,Icon,,"-20" ; -20 is for the USB icon
+
+; ==== Files Sources and Destinations ====
+
+[SourceDisksNames]
+1 = %Libusb_DiskName%
+
+[SourceDisksFiles]
+libusb0.sys = 1,\bin\x86,
+
+[SourceDisksFiles.amd64]
+libusb0.sys = 1,\bin\amd64,
+
+[DestinationDirs]
+libusb0_files_sys = 10,system32\drivers
+
+; ==== libusb0 Device driver ====
+
+[libusb0_files_sys]
+libusb0.sys,libusb0.sys
+
+; For each one of these, there must be one for Services !!!
+[LIBUSB0_DEV]
+CopyFiles = Libusb0_files_sys
+
+[LIBUSB0_DEV.HW]
+AddReg = libusb0_add_reg_hw
+
+[libusb0_add_reg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,libusb0.sys
+
+[libusb0_add_reg_hw]
+HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
+HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
+
+[LIBUSB0_DEV.Services]
+AddService = libusb0, 0x00000002, libusb0_add_service
+
+[libusb0_add_service]
+DisplayName = %libusb0_SvcDesc%
+ServiceType = 1
+StartType = 3
+ErrorControl = 0
+ServiceBinary = %12%\libusb0.sys
+
+; ==== Manufacturers ====
+
+[Manufacturer]
+"HCFR Association"=HCFR_Devices,NTx86,NTamd64
+"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
+"X-Rite"=X_Rite_Devices,NTx86,NTamd64
+"ColorVision"=ColorVision_Devices,NTx86,NTamd64
+"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
+"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
+"Image Engineering"=ImageEngineering_Devices,NTx86,NTamd64
+
+; ==== Devices ====
+
+[HCFR_Devices]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
+
+[GM_X_Rite_Devices]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices]
+"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+[ImageEngineering_Devices]
+"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
+
+
+[HCFR_Devices.NTx86]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices.NTx86]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices.NTx86]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices.NTx86]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
+
+[GM_X_Rite_Devices.NTx86]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices.NTx86]
+"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+[ImageEngineering_Devices.NTx86]
+"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
+
+
+[HCFR_Devices.NTamd64]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices.NTamd64]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices.NTamd64]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices.NTamd64]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
+
+[GM_X_Rite_Devices.NTamd64]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices.NTamd64]
+"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+[ImageEngineering_Devices.NTamd64]
+"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
+
diff --git a/usb/ArgyllCMS.inf.d b/usb/ArgyllCMS.inf.d
index c0809e9..c130cee 100644
--- a/usb/ArgyllCMS.inf.d
+++ b/usb/ArgyllCMS.inf.d
@@ -1,39 +1,39 @@
-
-[HCFR_Devices#PLAT#]
-"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
-"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
-
-[Sequel_Devices#PLAT#]
-"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
-
-[X_Rite_Devices#PLAT#]
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
-"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
-"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
-"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
-"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
-"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
-
-[ColorVision_Devices#PLAT#]
-"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
-"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
-"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
-"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
-"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
-
-[GM_X_Rite_Devices#PLAT#]
-"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
-"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
-"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
-"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
-"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
-
-[Hughski_Devices#PLAT#]
-"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
-
-[ImageEngineering_Devices#PLAT#]
-"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
-
+
+[HCFR_Devices#PLAT#]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices#PLAT#]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices#PLAT#]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices#PLAT#]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
+
+[GM_X_Rite_Devices#PLAT#]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices#PLAT#]
+"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+[ImageEngineering_Devices#PLAT#]
+"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
+
diff --git a/usb/ArgyllCMS.inf.t b/usb/ArgyllCMS.inf.t
index a185d03..635d9ef 100644
--- a/usb/ArgyllCMS.inf.t
+++ b/usb/ArgyllCMS.inf.t
@@ -1,112 +1,112 @@
-;--------------------------------------------------------------------------
-; Copyright 2012 Graeme W. Gill.
-;
-; Permission is hereby granted, free of charge, to any person obtaining a copy
-; of this file, to deal
-; in this file without restriction, including without limitation the rights
-; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-; copies of this file, and to permit persons to whom this file is
-; furnished to do so, subject to the following conditions:
-;
-; The above copyright notice and this permission notice shall be included in
-; all copies or substantial portions of this file.
-;
-; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
-; THIS FILE.
-;--------------------------------------------------------------------------
-
-; ==== Strings ====
-
-[Strings]
-
-DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
-
-Date = "01/17/2012" ; MM/DD/YYYY
-libusb0ver = "1.2.6.0"
-
-Libusb_ClassName = "Argyll LibUSB-win32 devices"
-Libusb_DiskName = "LibUSB-win32 Device Install Disk"
-
-libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
-
-; ==== Version ====
-
-[Version]
-Signature = "$Windows NT$"
-DriverVer = %Date%,%libusb0ver%
-Provider = "ArgyllCMS"
-
-; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
-Class = %Libusb_ClassName%
-ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
-CatalogFile = "ArgyllCMS.cat"
-CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
-
-[ClassInstall32]
-AddReg=class_install_add_reg
-
-[class_install_add_reg]
-HKR,,,,%Libusb_ClassName%
-HKR,,Icon,,"-20" ; -20 is for the USB icon
-
-; ==== Files Sources and Destinations ====
-
-[SourceDisksNames]
-1 = %Libusb_DiskName%
-
-[SourceDisksFiles]
-libusb0.sys = 1,\bin\x86,
-
-[SourceDisksFiles.amd64]
-libusb0.sys = 1,\bin\amd64,
-
-[DestinationDirs]
-libusb0_files_sys = 10,system32\drivers
-
-; ==== libusb0 Device driver ====
-
-[libusb0_files_sys]
-libusb0.sys,libusb0.sys
-
-; For each one of these, there must be one for Services !!!
-[LIBUSB0_DEV]
-CopyFiles = Libusb0_files_sys
-
-[LIBUSB0_DEV.HW]
-AddReg = libusb0_add_reg_hw
-
-[libusb0_add_reg]
-HKR,,DevLoader,,*ntkern
-HKR,,NTMPDriver,,libusb0.sys
-
-[libusb0_add_reg_hw]
-HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
-HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
-
-[LIBUSB0_DEV.Services]
-AddService = libusb0, 0x00000002, libusb0_add_service
-
-[libusb0_add_service]
-DisplayName = %libusb0_SvcDesc%
-ServiceType = 1
-StartType = 3
-ErrorControl = 0
-ServiceBinary = %12%\libusb0.sys
-
-; ==== Manufacturers ====
-
-[Manufacturer]
-"HCFR Association"=HCFR_Devices,NTx86,NTamd64
-"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
-"X-Rite"=X_Rite_Devices,NTx86,NTamd64
-"ColorVision"=ColorVision_Devices,NTx86,NTamd64
-"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
-"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
-"Image Engineering"=ImageEngineering_Devices,NTx86,NTamd64
-
-; ==== Devices ====
+;--------------------------------------------------------------------------
+; Copyright 2012 Graeme W. Gill.
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this file, to deal
+; in this file without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of this file, and to permit persons to whom this file is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of this file.
+;
+; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
+; THIS FILE.
+;--------------------------------------------------------------------------
+
+; ==== Strings ====
+
+[Strings]
+
+DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
+
+Date = "01/17/2012" ; MM/DD/YYYY
+libusb0ver = "1.2.6.0"
+
+Libusb_ClassName = "Argyll LibUSB-win32 devices"
+Libusb_DiskName = "LibUSB-win32 Device Install Disk"
+
+libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
+
+; ==== Version ====
+
+[Version]
+Signature = "$Windows NT$"
+DriverVer = %Date%,%libusb0ver%
+Provider = "ArgyllCMS"
+
+; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
+Class = %Libusb_ClassName%
+ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
+CatalogFile = "ArgyllCMS.cat"
+CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
+
+[ClassInstall32]
+AddReg=class_install_add_reg
+
+[class_install_add_reg]
+HKR,,,,%Libusb_ClassName%
+HKR,,Icon,,"-20" ; -20 is for the USB icon
+
+; ==== Files Sources and Destinations ====
+
+[SourceDisksNames]
+1 = %Libusb_DiskName%
+
+[SourceDisksFiles]
+libusb0.sys = 1,\bin\x86,
+
+[SourceDisksFiles.amd64]
+libusb0.sys = 1,\bin\amd64,
+
+[DestinationDirs]
+libusb0_files_sys = 10,system32\drivers
+
+; ==== libusb0 Device driver ====
+
+[libusb0_files_sys]
+libusb0.sys,libusb0.sys
+
+; For each one of these, there must be one for Services !!!
+[LIBUSB0_DEV]
+CopyFiles = Libusb0_files_sys
+
+[LIBUSB0_DEV.HW]
+AddReg = libusb0_add_reg_hw
+
+[libusb0_add_reg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,libusb0.sys
+
+[libusb0_add_reg_hw]
+HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
+HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
+
+[LIBUSB0_DEV.Services]
+AddService = libusb0, 0x00000002, libusb0_add_service
+
+[libusb0_add_service]
+DisplayName = %libusb0_SvcDesc%
+ServiceType = 1
+StartType = 3
+ErrorControl = 0
+ServiceBinary = %12%\libusb0.sys
+
+; ==== Manufacturers ====
+
+[Manufacturer]
+"HCFR Association"=HCFR_Devices,NTx86,NTamd64
+"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
+"X-Rite"=X_Rite_Devices,NTx86,NTamd64
+"ColorVision"=ColorVision_Devices,NTx86,NTamd64
+"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
+"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
+"Image Engineering"=ImageEngineering_Devices,NTx86,NTamd64
+
+; ==== Devices ====
diff --git a/usb/ArgyllCMS_x64.cat b/usb/ArgyllCMS_x64.cat
index 1bed3d1..16b3ffa 100644
--- a/usb/ArgyllCMS_x64.cat
+++ b/usb/ArgyllCMS_x64.cat
Binary files differ
diff --git a/xicc/Jamfile b/xicc/Jamfile
index 5a03901..169b471 100644
--- a/xicc/Jamfile
+++ b/xicc/Jamfile
@@ -124,16 +124,27 @@ Main monctest : monctest.c ;
#Main cam02vecplot : cam02vecplot.c : : : : : ../plot/libvrml ;
#Home = ' d:\usr\graeme ' and PWD = ' /src/argyll/xicc '
-if $(HOME) = "d:\\usr\\graeme" && $(PWD) = "/src/argyll/xicc" {
+if $(HOME) = "D:\\usr\\graeme" && $(PWD) = "/src/argyll/xicc" {
+ Echo "Creating test utilities" ;
#Create test TIFF file for cam02 conversion
Main cam02plot : cam02plot.c : : : $(TIFFINC) $(JPEGINC) : : ;
Main cam02logplot : cam02logplot.c : : : $(TIFFINC) $(JPEGINC) : : ;
Main cam02delplot : cam02delplot.c : : : $(TIFFINC) $(JPEGINC) : : ;
Main cam02vecplot : cam02vecplot.c : : : : : ../plot/libvrml ;
+ Main cusptest : cusptest.c : : : : : ../plot/libvrml ;
}
#Main t : t.c ;
+# diagnostic utility
+if [ GLOB [ NormPaths . ] : tennm.c ] {
+ Main tennm : tennm.c ;
+}
+
+if [ GLOB [ NormPaths . ] : cam16.c ] {
+ Main cam16vecplot : cam16vecplot.c cam16.c ;
+}
+
if $(BUILD_JUNK) {
LINKLIBS += ../render/librender ;
diff --git a/xicc/cam02.c b/xicc/cam02.c
index 376d2c8..a79aae1 100644
--- a/xicc/cam02.c
+++ b/xicc/cam02.c
@@ -197,7 +197,7 @@ double minj = 1e38, maxj = -1e38;
static void cam_free(cam02 *s);
static int set_view(struct _cam02 *s, ViewingCondition Ev, double Wxyz[3],
double La, double Yb, double Lv, double Yf, double Yg, double Gxyz[3],
- int hk);
+ int hk, double hkscale);
static int XYZ_to_cam(struct _cam02 *s, double *Jab, double *xyz);
static int cam_to_XYZ(struct _cam02 *s, double *xyz, double *Jab);
@@ -224,6 +224,9 @@ cam02 *new_cam02(void) {
s->XYZ_to_cam = XYZ_to_cam;
s->cam_to_XYZ = cam_to_XYZ;
+ /* Initialise default parameters */
+ s->hkscale = 1.0;
+
/* Set default range handling limits */
s->nldlimit = NLDLIMIT;
s->nldicept = NLDICEPT;
@@ -288,7 +291,8 @@ double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) *
double Yg, /* Flare as a fraction of the adapting/surround (Y range 0.0 .. 1.0) */
double Gxyz[3], /* The Glare white coordinates (typically the Ambient color) */
/* If <= 0 will Wxyz will be used. */
-int hk /* Flag, NZ to use Helmholtz-Kohlrausch effect */
+int hk, /* Flag, NZ to use Helmholtz-Kohlrausch effect */
+double hkscale /* HK effect scaling factor */
) {
double tt, t1, t2;
double tm[3][3];
@@ -378,6 +382,7 @@ int hk /* Flag, NZ to use Helmholtz-Kohlrausch effect */
s->Gxyz[2] = Wxyz[2];
}
s->hk = hk;
+ s->hkscale = hkscale;
/* The rgba vectors */
s->Va[0] = 1.0;
@@ -633,9 +638,10 @@ double XYZ[3]
TRACE(("XYZ inc flare = %f %f %f\n",xyz[0], xyz[1], xyz[2]))
- /* Spectrally sharpened cone responses, */
- /* Chromaticaly transformed sample value, */
- /* Transform from spectrally sharpened, to Hunt-Pointer_Estevez cone space. */
+ /* Transfor to spectrally sharpened cone responses, */
+ /* apply chromaticaly transform, */
+ /* and transform from spectrally sharpened to Hunt-Pointer_Estevez cone space, */
+ /* all in one step. */
icmMulBy3x3(rgbp, s->cc, xyz);
TRACE(("rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]))
@@ -949,7 +955,7 @@ double XYZ[3]
/* Helmholtz-Kohlrausch effect */
if (s->hk && J < 1.0) {
// double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
- double kk = HHKR_MUL * C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ double kk = s->hkscale * HHKR_MUL * C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
if (kk > 1e-6) /* Limit kk to a reasonable range */
kk = 1.0/(s->hklimit + 1.0/kk);
JJ = J + (1.0 - (J > 0.0 ? J : 0.0)) * kk;
@@ -1045,7 +1051,7 @@ double Jab[3]
/* Undo Helmholtz-Kohlrausch effect */
if (s->hk && J < 1.0) {
// double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
- double kk = HHKR_MUL * C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ double kk = s->hkscale * HHKR_MUL * C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
if (kk > 1e-6) /* Limit kk to a reasonable range */
kk = 1.0/(s->hklimit + 1.0/kk);
J = (JJ - kk)/(1.0 - kk);
diff --git a/xicc/cam02.h b/xicc/cam02.h
index 37443d3..9550bd5 100644
--- a/xicc/cam02.h
+++ b/xicc/cam02.h
@@ -7,7 +7,7 @@
* by Nathan Moroney, Mark D. Fairchild, Robert W.G. Hunt, Changjun Li,
* M. Ronnier Luo and Todd Newman, IS&T/SID Tenth Color Imaging
* Conference, with the addition of a Viewing Flare+Glare
- * model, and the Helmholtz-Kohlraush effect, using the equation
+ * model, and the Helmholtz-Kohlrausch effect, using the equation
* the Bradford-Hunt 96C model as detailed in Mark Fairchilds
* book "Color Appearance Models".
*
@@ -142,7 +142,8 @@ struct _cam02 {
double Yg, /* Glare as a fraction of the adapting/surround (range 0.0 .. 1.0) */
double Gxyz[3], /* The Glare white coordinates (ie. the Ambient color) */
/* If <= 0 will Wxyz will be used. */
- int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+ int hk, /* Flag, NZ to use Helmholtz-Kohlrausch effect */
+ double hkscale /* HK effect scaling factor */
);
/* Conversions. Return nz on error */
@@ -194,7 +195,8 @@ struct _cam02 {
double lA; /* JLIMIT Limited A */
/* Option flags, code not always enabled */
- int hk; /* Use Helmholtz-Kohlraush effect */
+ int hk; /* Use Helmholtz-Kohlrausch effect */
+ int hkscale; /* [1.0] Scale HK effect up/down from default */
int trace; /* Trace values through computation */
int retss; /* Return ss rather than Jab */
int range; /* (for cam02ref.h) return on range error */
diff --git a/xicc/cam02plot.c b/xicc/cam02plot.c
index f397e09..16b5aa5 100644
--- a/xicc/cam02plot.c
+++ b/xicc/cam02plot.c
@@ -577,7 +577,8 @@ main(int argc, char *argv[]) {
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[4], /* The Glare color coordinates (typically the Ambient color) */
- use_hk /* use Helmholtz-Kohlraush flag */
+ use_hk, /* use Helmholtz-Kohlraush flag */
+ 1.0 /* HK scaling factor */
);
/* Setup cam to convert from Jab */
@@ -595,7 +596,8 @@ main(int argc, char *argv[]) {
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[4], /* The Glare color coordinates (typically the Ambient color) */
- use_hk /* use Helmholtz-Kohlraush flag */
+ use_hk, /* use Helmholtz-Kohlraush flag */
+ 1.0 /* HK scaling factor */
);
/* Figure out the size of the raster */
diff --git a/xicc/cam02ref.h b/xicc/cam02ref.h
index 29f7d2a..28c3fd3 100644
--- a/xicc/cam02ref.h
+++ b/xicc/cam02ref.h
@@ -22,6 +22,8 @@
/* with the ICC convention (not 100.0 as assumed by the CIECAM spec.) */
/* Note that all whites are assumed to be normalised (ie. Y = 1.0) */
+#define HHKR_MUL 0.25
+
#undef DIAG /* Print internal value diagnostics for each conversion */
/* ---------------------------------- */
@@ -122,7 +124,8 @@ double Lv /* Luminence of white in the Viewing/Scene/Image field (cd/m^2) */
static void cam02ref_free(cam02ref *s);
static int cam02ref_set_view(cam02ref *s, ViewingCondition Ev, double Wxyz[3],
- double Yb, double La, double Lv, double Yf, double Yg, double Gxyz[3], int hk);
+ double Yb, double La, double Lv, double Yf, double Yg, double Gxyz[3],
+ int hk, double hkscale);
static int cam02ref_XYZ_to_cam(cam02ref *s, double *Jab, double *xyz);
static int cam02ref_cam_to_XYZ(cam02ref *s, double XYZ[3], double Jab[3]);
@@ -160,7 +163,8 @@ double Lv, /* Luminence of white in the Viewing/Scene/Image field (cd/m^2) */
double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
double Yg, /* Glare as a fraction of the adapting/surround (Y range 0.0 .. 1.0) */
double Gxyz[3], /* The Glare white coordinates (typically the Ambient color) */
-int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+int hk, /* Flag, NZ to use Helmholtz-Kohlraush effect */
+double hkscale /* HK effect scaling factor */
) {
double tt;
@@ -185,6 +189,7 @@ int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
s->Gxyz[2] = Wxyz[2];
}
s->hk = hk;
+ s->hkscale = hkscale;
/* Compute the internal parameters by category */
switch(s->Ev) {
@@ -442,7 +447,7 @@ double XYZ[3]
/* Helmholtz-Kohlraush effect */
if (s->hk && J < 1.0) {
- double JJ, kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ double JJ, kk = s->hkscale * HHKR_MUL * C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
if (kk > 0.9) /* Limit kk to a reasonable range */
kk = 0.9;
JJ = J + (1.0 - J) * kk;
@@ -508,7 +513,7 @@ double Jab[3]
/* Helmholtz-Kohlraush effect */
if (s->hk && J < 1.0) {
- double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ double kk = s->hkscale * HHKR_MUL * C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
if (kk > 0.9) /* Limit kk to a reasonable range */
kk = 0.9;
J = (J - kk)/(1.0 - kk);
diff --git a/xicc/cam02test.c b/xicc/cam02test.c
index eba27d6..fb7d98e 100644
--- a/xicc/cam02test.c
+++ b/xicc/cam02test.c
@@ -562,7 +562,8 @@ main(void) {
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
sp_white[c],/* The Glare color coordinates (typically the Ambient color) */
- USE_HK /* use Helmholtz-Kohlraush flag */
+ USE_HK, /* use Helmholtz-Kohlraush flag */
+ 1.0 /* Normal Helmholtz-Kohlraush scale */
);
cam->set_view(
@@ -575,7 +576,8 @@ main(void) {
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
sp_white[c],/* The Glare color coordinates (typically the Ambient color) */
- USE_HK /* use Helmholtz-Kohlraush flag */
+ USE_HK, /* use Helmholtz-Kohlraush flag */
+ 1.0 /* Normal Helmholtz-Kohlraush scale */
);
camr->nldlimit = cam->nldlimit;
@@ -716,7 +718,8 @@ main(void) {
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[c], /* The Glare color coordinates (typically the Ambient color) */
- USE_HK /* use Helmholtz-Kohlraush flag */
+ USE_HK, /* use Helmholtz-Kohlraush flag */
+ 1.0 /* Normal Helmholtz-Kohlraush scale */
);
cam->set_view(
@@ -729,7 +732,8 @@ main(void) {
0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.00, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[c], /* The Glare color coordinates (typically the Ambient color) */
- USE_HK /* use Helmholtz-Kohlraush flag */
+ USE_HK, /* use Helmholtz-Kohlraush flag */
+ 1.0 /* Normal Helmholtz-Kohlraush scale */
);
/* Make reference return error where it's going to disagree with implementation */
@@ -950,7 +954,8 @@ main(void) {
0.0, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.0, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[c], /* The Glare color coordinates (typically the Ambient color) */
- USE_HK /* use Helmholtz-Kohlraush flag */
+ USE_HK, /* use Helmholtz-Kohlraush flag */
+ 1.0 /* Normal Helmholtz-Kohlraush scale */
);
#ifdef INVTEST1
@@ -1132,7 +1137,8 @@ main(void) {
0.0, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
0.0, /* Glare as a fraction of the ambient (Y range 0.0 .. 1.0) */
white[c], /* The Glare color coordinates (typically the Ambient color) */
- USE_HK /* use Helmholtz-Kohlraush flag */
+ USE_HK, /* use Helmholtz-Kohlraush flag */
+ 1.0 /* Normal Helmholtz-Kohlraush scale */
);
#ifdef TESTINV1
diff --git a/xicc/ccmx.c b/xicc/ccmx.c
index 538f181..7206f31 100644
--- a/xicc/ccmx.c
+++ b/xicc/ccmx.c
@@ -3,6 +3,9 @@
* Argyll Color Correction System
* Colorimeter Correction Matrix
*
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 19/8/2010
*
@@ -16,6 +19,7 @@
* on other libraries that are licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3.
*/
+
/*
* TTBD:
*/
@@ -34,7 +38,7 @@
#include "icc.h"
#else
#include "numsup.h"
-#include "conv.h"
+#include "sa_conv.h"
#endif
#include "cgats.h"
#include "disptechs.h"
@@ -146,7 +150,7 @@ char *outname /* Filename to write to */
static int buf_write_ccmx(
ccmx *p,
unsigned char **buf, /* Return allocated buffer */
-int *len /* Return length */
+size_t *len /* Return length */
) {
int rv;
cgats *ocg; /* CGATS structure */
@@ -353,7 +357,7 @@ char *inname /* Filename to read from */
static int buf_read_ccmx(
ccmx *p, /* This */
unsigned char *buf,
-int len
+size_t len
) {
int rv;
cgatsFile *fp;
@@ -685,6 +689,7 @@ int refrmode, /* Display refresh mode, -1 = unknown, 0 = n, 1 = yes */
int cbid, /* Display type calibration base index, 0 = unknown */
char *sel, /* UI selector characters - NULL for none */
char *refd, /* Reference spectrometer description (optional) */
+int oem, /* NZ if OEM source */
int npat, /* Number of samples in following arrays */
double (*refs)[3], /* Array of XYZ values from spectrometer */
double (*cols)[3] /* Array of XYZ values from colorimeter */
diff --git a/xicc/ccmx.h b/xicc/ccmx.h
index 94263e0..03d29d1 100644
--- a/xicc/ccmx.h
+++ b/xicc/ccmx.h
@@ -5,6 +5,9 @@
* Argyll Color Correction System
* Colorimeter Correction Matrix support.
*
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 19/8/2010
*
@@ -19,6 +22,10 @@
*
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/*
* This object provides storage and application of a 3x3 XYZ
* corretion matrix suitable for corrected a particular
@@ -46,13 +53,13 @@ struct _ccmx {
/* write a CGATS .ccmx file to a memory buffer. */
/* return nz on error, with message in err[] */
- int (*buf_write_ccmx)(struct _ccmx *p, unsigned char **buf, int *len);
+ int (*buf_write_ccmx)(struct _ccmx *p, unsigned char **buf, size_t *len);
/* read from a CGATS .ccmx file */
int (*read_ccmx)(struct _ccmx *p, char *filename);
/* read from a CGATS .ccmx file from a memory buffer. */
- int (*buf_read_ccmx)(struct _ccmx *p, unsigned char *buf, int len);
+ int (*buf_read_ccmx)(struct _ccmx *p, unsigned char *buf, size_t len);
/* Correct an XYZ value */
void (*xform) (struct _ccmx *p,
@@ -83,6 +90,10 @@ struct _ccmx {
/* Create a new, uninitialised ccmx */
ccmx *new_ccmx(void);
+#ifdef __cplusplus
+ }
+#endif
+
#endif /* CCMX_H */
diff --git a/xicc/ccss.c b/xicc/ccss.c
index 75075c1..aae278e 100644
--- a/xicc/ccss.c
+++ b/xicc/ccss.c
@@ -2,7 +2,9 @@
/*
* Argyll Color Correction System
* Colorimeter Correction Matrix
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 9/8/2010
*
@@ -13,6 +15,7 @@
* see the License2.txt file for licencing details.
*/
+
/*
* TTBD:
*/
@@ -31,7 +34,7 @@
#include "icc.h"
#else
#include "numsup.h"
-#include "conv.h"
+#include "sa_conv.h"
#endif
#include "cgats.h"
#include "xspect.h"
@@ -201,7 +204,7 @@ char *outname /* Filename to write to */
static int buf_write_ccss(
ccss *p,
unsigned char **buf, /* Return allocated buffer */
-int *len /* Return length */
+size_t *len /* Return length */
) {
int rv;
cgats *ocg; /* CGATS structure */
@@ -231,7 +234,7 @@ int *len /* Return length */
}
/* Get the buffer the ccss has been written to */
- if (fp->get_buf(fp, buf, (size_t *)len)) {
+ if (fp->get_buf(fp, buf, len)) {
strcpy(p->err, "cgatsFileMem get_buf failed");
return 2;
}
@@ -434,7 +437,7 @@ char *inname /* Filename to read from */
static int buf_read_ccss(
ccss *p, /* This */
unsigned char *buf,
-int len
+size_t len
) {
int rv;
cgatsFile *fp;
diff --git a/xicc/ccss.h b/xicc/ccss.h
index 8258031..dbcfbc1 100644
--- a/xicc/ccss.h
+++ b/xicc/ccss.h
@@ -4,7 +4,9 @@
/*
* Argyll Color Correction System
* Colorimeter Calibration Spectral Set support.
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 18/8/2011
*
@@ -17,6 +19,10 @@
* Based on ccmx.h
*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/*
* This object provides storage and application of emisive spectral
* samples that can be used to compute calibration for suitable
@@ -42,7 +48,7 @@ struct _ccss {
/* write a CGATS .ccss file to a memory buffer. */
/* return nz on error, with message in err[] */
- int (*buf_write_ccss)(struct _ccss *p, unsigned char **buf, int *len);
+ int (*buf_write_ccss)(struct _ccss *p, unsigned char **buf, size_t *len);
/* read from a CGATS .ccss file */
/* return nz on error, with message in err[] */
@@ -50,7 +56,7 @@ struct _ccss {
/* read from a CGATS .ccss file from a memory buffer. */
/* return nz on error, with message in err[] */
- int (*buf_read_ccss)(struct _ccss *p, unsigned char *buf, int len);
+ int (*buf_read_ccss)(struct _ccss *p, unsigned char *buf, size_t len);
/* Private: */
/* (All char * are owned by ccss) */
@@ -75,6 +81,10 @@ struct _ccss {
/* Create a new, uninitialised ccss */
ccss *new_ccss(void);
+#ifdef __cplusplus
+ }
+#endif
+
#endif /* CCSS_H */
diff --git a/xicc/ccttest.c b/xicc/ccttest.c
index 52bbdac..1b859b5 100644
--- a/xicc/ccttest.c
+++ b/xicc/ccttest.c
@@ -238,9 +238,18 @@ main(
#endif
if (in_name[0] != '\000') {
- if (read_xspect(&sp, in_name) != 0)
+ inst_meas_type mt;
+
+ if (read_xspect(&sp, &mt, in_name) != 0)
error ("Unable to read custom spectrum '%s'",in_name);
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Custom illuminant '%s' is wrong measurement type",in_name);
+
sprintf(buf, "File '%s'",in_name);
do_spec(buf, &sp);
diff --git a/xicc/extractttag.c b/xicc/extractttag.c
index 2c26bda..98c7835 100644
--- a/xicc/extractttag.c
+++ b/xicc/extractttag.c
@@ -32,7 +32,6 @@
#include "numlib.h"
#include "icc.h"
#include "xicc.h"
-#include "ui.h"
#define MXTGNMS 30
diff --git a/xicc/fakeCMY.c b/xicc/fakeCMY.c
index b27f2d1..0863cfb 100644
--- a/xicc/fakeCMY.c
+++ b/xicc/fakeCMY.c
@@ -31,7 +31,6 @@
#include "xicc.h"
#include "cgats.h"
#include "targen.h"
-#include "ui.h"
#define EXTRA_NEUTRAL 50 /* Crude way of increasing weighting */
@@ -257,14 +256,15 @@ main(
for (j = 0; j < 3; j++)
gc[j] = 0;
- for (;;) { /* For all grid points */
+ /* Add CMY grid surface points */
+ for (;;) { /* Generate all grid points */
/* Check if this position is on the CMY surface */
for (j = 0; j < 3; j++) {
if (gc[j] == 0 || gc[j] == (tres-1))
break;
}
- if (j < 3) { /* On the surface */
+ if (j < 3) { /* On the surface, so add a point */
/* Make sure there is room */
if (fxno >= fxlist_a) {
@@ -274,7 +274,7 @@ main(
}
for (j = 0; j < 3; j++)
fxlist[fxno].p[j] = gc[j]/(tres-1.0);
- fxlist[fxno].p[3] = 0.0;
+ fxlist[fxno].p[3] = 0.0; /* K = 0 */
fxno++;
}
@@ -289,7 +289,8 @@ main(
break; /* Done grid */
}
- for (i = 1; i < ((EXTRA_NEUTRAL * gres)-1); i++) { /* For all grey axis points */
+ /* Add neutral axis points */
+ for (i = 1; i < ((EXTRA_NEUTRAL * gres)-1); i++) {
/* Make sure there is room */
if (fxno >= fxlist_a) {
@@ -299,7 +300,7 @@ main(
}
for (j = 0; j < 3; j++)
fxlist[fxno].p[j] = i/((EXTRA_NEUTRAL * gres)-1.0);
- fxlist[fxno].p[3] = 0.0;
+ fxlist[fxno].p[3] = 0.0; /* K = 0 */
fxno++;
}
@@ -310,6 +311,9 @@ main(
//printf("~1 initial lookup %f %f %f -> %f %f %f\n", fxlist[i].p[0], fxlist[i].p[1], fxlist[i].p[2], fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
}
+ /* A CMYK black will be deeper than CMY0, so we need to figure out */
+ /* how to scale the initial values to fully occupy the CMYK gamut. */
+
/* Figure out the general scale at the black end */
{
double dval[4];
diff --git a/xicc/fbview.c b/xicc/fbview.c
index 07a9170..482ba5f 100644
--- a/xicc/fbview.c
+++ b/xicc/fbview.c
@@ -1,7 +1,10 @@
/*
+ * See xfbview !
+ *
* International Color Consortium Format Library (icclib)
* View the gamut clipping implemented by the bwd profile.
+ * abscol intent, asumes CMYK
*
* Author: Graeme W. Gill
* Date: 2000/12/8
@@ -58,7 +61,7 @@ double absdiff(double in1[3], double in2[3]) {
/* ---------------------------------------- */
void usage(void) {
- fprintf(stderr,"View bwd table clipping of an ICC file, , Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"View abscol bwd table clipping of an ICC file, , Version %s\n",ARGYLL_VERSION_STR);
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
fprintf(stderr,"usage: fbtest [-v] infile\n");
fprintf(stderr," -v verbose\n");
diff --git a/xicc/iccgamut.c b/xicc/iccgamut.c
index 77f8fdd..ecbab7f 100644
--- a/xicc/iccgamut.c
+++ b/xicc/iccgamut.c
@@ -42,14 +42,13 @@
#include "gamut.h"
#include "counters.h"
#include "vrml.h"
-#include "ui.h"
static void diag_gamut(icxLuBase *p, double detail, int doaxes,
double tlimit, double klimit, char *outname);
void usage(char *diag) {
int i;
- fprintf(stderr,"Create Lab/Jab gamut plot Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Create ICC profile Lab/Jab gamut & plot Version %s\n",ARGYLL_VERSION_STR);
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
fprintf(stderr,"usage: iccgamut [options] profile\n");
if (diag != NULL)
@@ -89,7 +88,8 @@ void usage(char *diag) {
fprintf(stderr," g:glare Flare light %% of ambient (default %d)\n",XICC_DEFAULT_GLARE);
fprintf(stderr," g:X:Y:Z Flare color as XYZ (default media white, Abs: D50)\n");
fprintf(stderr," g:x:y Flare color as x, y\n");
- fprintf(stderr," -s Create special cube surface topology plot\n");
+ fprintf(stderr," -x pcent Expand/compress gamut cylindrically by percent\n");
+ fprintf(stderr," -s Create special cube surface topology plot\n");
fprintf(stderr,"\n");
exit(1);
}
@@ -126,6 +126,7 @@ main(int argc, char *argv[]) {
double vc_g = -1.0; /* Glare % overide */
double vc_gXYZ[3] = {-1.0, -1.0, -1.0}; /* Glare color override in XYZ */
double vc_gxy[2] = {-1.0, -1.0}; /* Glare color override in x,y */
+ double expand = 1.0; /* Expand gamut cylindrically */
icxLuBase *luo;
@@ -288,6 +289,18 @@ main(int argc, char *argv[]) {
usage("Parameter after flag -d seems out of range");
}
+ /* Expand gamut cylindrically */
+ else if (argv[fa][1] == 'x') {
+ double rr;
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -x");
+ rr = atof(na)/100.0;
+
+ if (rr < 0.01 || rr > 100.0)
+ usage("-x ratio is out of range");
+ expand = rr;
+ }
+
/* Viewing conditions */
else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
fa = nfa;
@@ -489,6 +502,19 @@ main(int argc, char *argv[]) {
if ((gam = luo->get_gamut(luo, gamres)) == NULL)
error ("%d, %s",xicco->errc, xicco->err);
+ /* Expand gamut cylindrically */
+ if (expand != 1.0) {
+ gamut *xgam;
+
+ if ((xgam = new_gamut(1.0, 0, 0)) == NULL
+ || xgam->exp_cyl(xgam, gam, expand)) {
+ error ("Creating expanded gamut failed");
+ }
+
+ gam->del(gam);
+ gam = xgam;
+ }
+
if (gam->write_gam(gam, out_name))
error ("write gamut failed on '%s'",out_name);
diff --git a/xicc/mpplu.c b/xicc/mpplu.c
index 11ddb76..09fe18c 100644
--- a/xicc/mpplu.c
+++ b/xicc/mpplu.c
@@ -214,10 +214,20 @@ main(int argc, char *argv[]) {
spec = 1;
illum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
spec = 1;
illum = icxIT_custom;
- if (read_xspect(&cust_illum, na) != 0)
+ if (read_xspect(&cust_illum, &mt, na) != 0)
usage();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash) {
+ error("Custom illuminant '%s' is wrong measurement type",na);
+ }
}
}
diff --git a/xicc/revfix.c b/xicc/revfix.c
index 2add264..ee9662a 100644
--- a/xicc/revfix.c
+++ b/xicc/revfix.c
@@ -34,7 +34,6 @@
#include "aconfig.h"
#include "numlib.h"
#include "xicc.h"
-#include "ui.h"
#define USE_CAM_CLIP_OPT /* Clip in CAM Jab space rather than Lab */
#undef DEBUG /* Print each value changed */
diff --git a/xicc/specplot.c b/xicc/specplot.c
index 6f38f37..9e43856 100644
--- a/xicc/specplot.c
+++ b/xicc/specplot.c
@@ -38,6 +38,7 @@ static int do_spec(
char name[MAXGRAPHS][200],
xspect *sp,
int nsp, /* Number of sp */
+ inst_meas_type mt, /* Measurement type */
int dozero, /* Include zero in the range */
int douv, /* Do variation of added UV test */
double uvmin,
@@ -103,69 +104,95 @@ static int do_spec(
xsp_setUV(&tsp, &sp[k], uv);
}
- /* Compute XYZ of illuminant */
- if (icx_ill_sp2XYZ(xyz, icxOT_CIE_1931_2, NULL, icxIT_custom, 0, &tsp) != 0)
- warning("icx_sp_temp2XYZ returned error");
-
- icmXYZ2Yxy(Yxy, xyz);
- icmXYZ2Lab(&icmD50, Lab, xyz);
-
printf("Type = %s [%s]\n",name[k], color[k]);
- printf("XYZ = %f %f %f, x,y = %f %f\n", xyz[0], xyz[1], xyz[2], Yxy[1], Yxy[2]);
- printf("D50 L*a*b* = %f %f %f\n", Lab[0], Lab[1], Lab[2]);
-
-#ifndef NEVER
- /* Test density */
- {
- double dens[4];
-
- xsp_Tdensity(dens, &tsp);
-
- printf("CMYV density = %f %f %f %f\n", dens[0], dens[1], dens[2], dens[3]);
- }
-#endif
-
- /* Compute CCT */
- if ((cct = icx_XYZ2ill_ct(cct_xyz, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, xyz, NULL, 0)) < 0)
- warning("Got bad cct\n");
-
- /* Compute VCT */
- if ((vct = icx_XYZ2ill_ct(vct_xyz, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, xyz, NULL, 1)) < 0)
- warning("Got bad vct\n");
- printf("CCT = %f, VCT = %f\n",cct, vct);
-
- /* Compute CDT */
- if ((cct = icx_XYZ2ill_ct(cct_xyz, icxIT_Dtemp, icxOT_CIE_1931_2, NULL, xyz, NULL, 0)) < 0)
- warning("Got bad cct\n");
+ if (mt == inst_mrt_none
+ || mt == inst_mrt_emission
+ || mt == inst_mrt_ambient
+ || mt == inst_mrt_emission_flash
+ || mt == inst_mrt_ambient_flash) {
+
+ /* Compute XYZ of illuminant */
+ if (icx_ill_sp2XYZ(xyz, icxOT_CIE_1931_2, NULL, icxIT_custom, 0, &tsp) != 0)
+ warning("icx_ill_sp2XYZ returned error");
+
+ icmXYZ2Yxy(Yxy, xyz);
+ icmXYZ2Lab(&icmD50, Lab, xyz);
- /* Compute VDT */
- if ((vct = icx_XYZ2ill_ct(vct_xyz, icxIT_Dtemp, icxOT_CIE_1931_2, NULL, xyz, NULL, 1)) < 0)
- warning("Got bad vct\n");
+ printf("XYZ = %f %f %f, x,y = %f %f\n", xyz[0], xyz[1], xyz[2], Yxy[1], Yxy[2]);
+ printf("D50 L*a*b* = %f %f %f\n", Lab[0], Lab[1], Lab[2]);
+
+ /* Compute CCT */
+ if ((cct = icx_XYZ2ill_ct(cct_xyz, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, xyz, NULL, 0)) < 0)
+ warning("Got bad cct\n");
+
+ /* Compute VCT */
+ if ((vct = icx_XYZ2ill_ct(vct_xyz, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, xyz, NULL, 1)) < 0)
+ warning("Got bad vct\n");
+
+ printf("CCT = %f, VCT = %f\n",cct, vct);
+
+ /* Compute CDT */
+ if ((cct = icx_XYZ2ill_ct(cct_xyz, icxIT_Dtemp, icxOT_CIE_1931_2, NULL, xyz, NULL, 0)) < 0)
+ warning("Got bad cct\n");
+
+ /* Compute VDT */
+ if ((vct = icx_XYZ2ill_ct(vct_xyz, icxIT_Dtemp, icxOT_CIE_1931_2, NULL, xyz, NULL, 1)) < 0)
+ warning("Got bad vct\n");
+
+ printf("CDT = %f, VDT = %f\n",cct, vct);
+
+ {
+ int invalid = 0;
+ double RR[14];
+ double cri;
+ cri = icx_CIE1995_CRI(&invalid, RR, &tsp);
+ printf("CRI = %.1f [ R9 = %.1f ]%s\n",cri,RR[9-1],invalid ? " (Invalid)" : "");
+ }
+ {
+ int invalid = 0;
+ double tlci;
+ tlci = icx_EBU2012_TLCI(&invalid, &tsp);
+ printf("TLCI = %.1f%s\n",tlci,invalid ? " (Invalid)" : "");
+ }
+
+ /* Use modern color difference - gives a better visual match */
+ icmAry2XYZ(wp, vct_xyz);
+ icmXYZ2Lab(&wp, cct_lab, cct_xyz);
+ icmXYZ2Lab(&wp, vct_lab, vct_xyz);
+ de = icmCIE2K(cct_lab, vct_lab);
+ printf("CIEDE2000 Delta E = %f\n",de);
+
+ } else if (mt == inst_mrt_none
+ || mt == inst_mrt_reflective
+ || mt == inst_mrt_transmissive) {
+
+ printf("CIE values under D50 illuminant:\n");
- printf("CDT = %f, VDT = %f\n",cct, vct);
+ if (icx_sp2XYZ(xyz, icxOT_CIE_1931_2, NULL, icxIT_D50, 0, NULL, &tsp) != 0)
+ warning("icx_sp2XYZ returned error");
+
+ icmXYZ2Yxy(Yxy, xyz);
+ icmXYZ2Lab(&icmD50, Lab, xyz);
- {
- int invalid = 0;
- double RR[14];
- double cri;
- cri = icx_CIE1995_CRI(&invalid, RR, &tsp);
- printf("CRI = %.1f [ R9 = %.1f ]%s\n",cri,RR[9-1],invalid ? " (Invalid)" : "");
- }
- {
- int invalid = 0;
- double tlci;
- tlci = icx_EBU2012_TLCI(&invalid, &tsp);
- printf("TLCI = %.1f%s\n",tlci,invalid ? " (Invalid)" : "");
+ printf("XYZ = %f %f %f, x,y = %f %f\n", xyz[0], xyz[1], xyz[2], Yxy[1], Yxy[2]);
+ printf("D50 L*a*b* = %f %f %f\n", Lab[0], Lab[1], Lab[2]);
+
+#ifndef NEVER
+ /* Test density */
+ {
+ double dens[4];
+
+ xsp_Tdensity(dens, &tsp);
+
+ printf("CMYV density = %f %f %f %f\n", dens[0], dens[1], dens[2], dens[3]);
+ }
+#endif
+
+ } else {
+ printf("Unhandled measurement type '%s'\n",meas_type2str(mt));
}
- /* Use modern color difference - gives a better visual match */
- icmAry2XYZ(wp, vct_xyz);
- icmXYZ2Lab(&wp, cct_lab, cct_xyz);
- icmXYZ2Lab(&wp, vct_lab, vct_xyz);
- de = icmCIE2K(cct_lab, vct_lab);
- printf("CIEDE2000 Delta E = %f\n",de);
-
/* Plot spectrum out */
for (i = 0; i < XRES; i++) {
double ww;
@@ -285,13 +312,14 @@ main(
/* Until we run out */
for (;;) {
int i, nret, nreq;
+ inst_meas_type mt;
/* If we've got to the limit of each plot, */
- /* or at least one and there are no more files, */
- /* or at least one and we're not combining files and at start of a new file */
+ /* or at least one and we're not combining files and at start of a new file, */
+ /* or at least one and there are no more files */
if (nsp >= MAXGRAPHS || (nsp > 0 && ((!comb && soff == 0) || fa >= argc))) {
/* Plot what we've got */
- do_spec(buf, sp, nsp, zero, douv, uvmin, uvmax);
+ do_spec(buf, sp, nsp, mt, zero, douv, uvmin, uvmax);
nsp = 0;
}
@@ -300,9 +328,11 @@ main(
/* Read as many spectra from the file as possible */
nreq = MAXGRAPHS - nsp;
- if (read_nxspect(&sp[nsp], argv[fa], &nret, soff, nreq, 0) != 0) {
+
+ if (read_nxspect(&sp[nsp], &mt, argv[fa], &nret, soff, nreq, 0) != 0) {
error ("Unable to read custom spectrum, CMF or CCSS '%s'",argv[fa]);
}
+
for (i = 0; i < nret; i++) {
xspect_denorm(&sp[nsp + i]);
sprintf(buf[nsp + i],"File '%s' spect %d",argv[fa], soff + i);
@@ -353,7 +383,7 @@ main(
error ("standardIlluminant returned error for %d (%s)",ilType,inm);
strcpy(buf[0],inm);
- do_spec(buf, sp, 1, zero, douv, uvmin, uvmax);
+ do_spec(buf, sp, 1, inst_mrt_ambient, zero, douv, uvmin, uvmax);
}
/* For each material and illuminant */
@@ -375,7 +405,7 @@ main(
sprintf(buf[0], "%s at %f", k == 0 ? "Daylight" : "Black body", temp);
- do_spec(buf, sp, 1, zero, douv, uvmin, uvmax);
+ do_spec(buf, sp, 1, inst_mrt_ambient, zero, douv, uvmin, uvmax);
}
}
diff --git a/xicc/specsubsamp.c b/xicc/specsubsamp.c
index 4163ee2..f4ac1e4 100644
--- a/xicc/specsubsamp.c
+++ b/xicc/specsubsamp.c
@@ -91,9 +91,18 @@ main(
} else if (strcmp(na, "F10") == 0) {
illum = icxIT_F10;
} else { /* Assume it's a filename */
+ inst_meas_type mt;
+
illum = icxIT_custom;
- if (read_xspect(&cust_illum, na) != 0)
+ if (read_xspect(&cust_illum, &mt, na) != 0)
usage();
+
+ if (mt != inst_mrt_none
+ && mt != inst_mrt_emission
+ && mt != inst_mrt_ambient
+ && mt != inst_mrt_emission_flash
+ && mt != inst_mrt_ambient_flash)
+ error("Custom illuminant '%s' is wrong measurement type",na);
}
}
diff --git a/xicc/spectest.c b/xicc/spectest.c
index c340e98..bed19e0 100644
--- a/xicc/spectest.c
+++ b/xicc/spectest.c
@@ -33,8 +33,8 @@
#include "numlib.h"
#ifdef DOPLOT
#include "plot.h"
-#endif
#include "ui.h"
+#endif
/* Spectrolino filter "D65" illuminant */
diff --git a/xicc/spectest2.c b/xicc/spectest2.c
index 3fd574f..cec6359 100644
--- a/xicc/spectest2.c
+++ b/xicc/spectest2.c
@@ -31,8 +31,8 @@
#include "numlib.h"
#ifdef DOPLOT
#include "plot.h"
-#endif
#include "ui.h"
+#endif
/* Normal 'A' spectra, then UV filtered version */
diff --git a/xicc/tiffgamut.c b/xicc/tiffgamut.c
index e373fbd..38b6b6c 100644
--- a/xicc/tiffgamut.c
+++ b/xicc/tiffgamut.c
@@ -46,7 +46,6 @@
#include "xicc.h"
#include "sort.h"
#include "vrml.h"
-#include "ui.h"
#undef NOCAMGAM_CLIP /* No clip to CAM gamut before CAM lookup */
#undef DEBUG /* Dump filter cell contents */
@@ -99,6 +98,7 @@ void usage(void) {
fprintf(stderr," g:glare Flare light %% of ambient (default %d)\n",XICC_DEFAULT_GLARE);
fprintf(stderr," g:X:Y:Z Flare color as XYZ (default media white, Abs: D50)\n");
fprintf(stderr," g:x:y Flare color as x, y\n");
+ fprintf(stderr," -x pcent Expand/compress gamut cylindrically by percent\n");
fprintf(stderr," -O outputfile Override the default output filename.\n");
exit(1);
}
@@ -355,6 +355,7 @@ main(int argc, char *argv[]) {
double vc_g = -1.0; /* Glare % overide */
double vc_gXYZ[3] = {-1.0, -1.0, -1.0}; /* Glare color override in XYZ */
double vc_gxy[2] = {-1.0, -1.0}; /* Glare color override in x,y */
+ double expand = 1.0; /* Expand gamut cylindrically by ratio */
icxLuBase *luo = NULL; /* Generic lookup object */
icColorSpaceSignature ins = icSigLabData, outs; /* Type of input and output spaces */
int inn, outn; /* Number of components */
@@ -581,6 +582,18 @@ main(int argc, char *argv[]) {
filter = 1;
}
+ /* Expand gamut cylindrically */
+ else if (argv[fa][1] == 'x') {
+ double rr;
+ fa = nfa;
+ if (na == NULL) usage();
+ rr = atof(na)/100.0;
+
+ if (rr < 0.01 || rr > 100.0)
+ usage();
+ expand = rr;
+ }
+
/* Output file name */
else if (argv[fa][1] == 'O') {
fa = nfa;
@@ -760,7 +773,7 @@ main(int argc, char *argv[]) {
error("new_icxcam failed");
cam->set_view(cam, vc.Ev, vc.Wxyz, vc.La, vc.Yb, vc.Lv, vc.Yf, vc.Yg, vc.Gxyz,
- XICC_USE_HK);
+ XICC_USE_HK, vc.hkscale);
}
/* Establish the PCS range if we are filtering */
@@ -1134,6 +1147,19 @@ main(int argc, char *argv[]) {
if (verb)
printf("Output Gamut file '%s'\n",out_name);
+ /* Expand gamut cylindrically */
+ if (expand != 1.0) {
+ gamut *xgam;
+
+ if ((xgam = new_gamut(1.0, 0, 0)) == NULL
+ || xgam->exp_cyl(xgam, gam, expand)) {
+ error ("Creating expanded gamut failed");
+ }
+
+ gam->del(gam);
+ gam = xgam;
+ }
+
/* Create the VRML/X3D file */
if (gam->write_gam(gam,out_name))
error ("write gamut failed on '%s'",out_name);
diff --git a/xicc/tiffgmts.c b/xicc/tiffgmts.c
index 446ea5c..592c2dd 100644
--- a/xicc/tiffgmts.c
+++ b/xicc/tiffgmts.c
@@ -42,7 +42,6 @@
#include "xicc.h"
#include "vrml.h"
#include "sort.h"
-#include "ui.h"
#define DE_SPACE 3 /* Delta E of spacing for output points */
#undef DEBUG_PLOT
diff --git a/xicc/xcal.c b/xicc/xcal.c
index 4400745..4a5b37e 100644
--- a/xicc/xcal.c
+++ b/xicc/xcal.c
@@ -1,8 +1,11 @@
/*
- * Argyll Color Correction System
* Calibration curve class.
+ */
+
+/*
*
+ * Argyll Color Correction System
* Author: Graeme W. Gill
* Date: 30/10/2005
*
@@ -26,10 +29,20 @@
#include <sys/types.h>
#include <time.h>
#include <string.h>
+#ifndef SALONEINSTLIB
#include "copyright.h"
#include "aconfig.h"
#include "numlib.h"
#include "xicc.h"
+#else
+#include "sa_config.h"
+#include "numsup.h"
+#include "rspl1.h"
+#include "cgats.h"
+#include "sa_conv.h"
+#include "xcolorants.h"
+#include "xcal.h"
+#endif /* SALONEINSTLIB */
#ifdef NT /* You'd think there might be some standards.... */
# ifndef __BORLANDC__
@@ -196,11 +209,14 @@ static int xcal_read_cgats(xcal *p, cgats *tcg, int table, char *filename) {
return 0;
}
+#ifndef SALONEINSTLIB
+
/* Read a calibration file from an ICC vcgt tag */
/* Return nz if this fails */
int xcal_read_icc(xcal *p, icc *c) {
icmVideoCardGamma *vg;
icmTextDescription *td;
+ icmText *tx;
int res, i, j;
/* See if there is a vcgt tag */
@@ -229,8 +245,8 @@ int xcal_read_icc(xcal *p, icc *c) {
if ((td = (icmTextDescription *)c->read_tag(c, icSigProfileDescriptionTag)) != NULL) {
p->xpi.profDesc = strdup(td->desc);
}
- if ((td = (icmTextDescription *)c->read_tag(c, icSigCopyrightTag)) != NULL) {
- p->xpi.copyright = strdup(td->desc);
+ if ((tx = (icmText *)c->read_tag(c, icSigCopyrightTag)) != NULL) {
+ p->xpi.copyright = strdup(tx->data);
}
/* Decide the lut resolution */
@@ -280,6 +296,8 @@ int xcal_read_icc(xcal *p, icc *c) {
return 0;
}
+#endif /* !SALONEINSTLIB */
+
/* Read a calibration file */
/* Return nz if this fails */
static int xcal_read(xcal *p, char *filename) {
@@ -342,7 +360,11 @@ static int xcal_write_cgats(xcal *p, cgats *tcg) {
else if (p->devclass == icSigDisplayClass)
tcg->add_kword(tcg, table, "DEVICE_CLASS","DISPLAY", NULL);
else {
+#ifdef SALONEINSTLIB
+ sprintf(p->err,"Unknown device class 0x%x",p->devclass);
+#else
sprintf(p->err,"Unknown device class '%s'",icm2str(icmProfileClassSignature,p->devclass));
+#endif
return p->errc = 1;
}
@@ -382,7 +404,7 @@ static int xcal_write_cgats(xcal *p, cgats *tcg) {
return p->errc = 2;
}
- calres = p->cals[0]->g.res[0];
+ calres = p->cals[0]->get_res(p->cals[0])[0];
for (i = 0; i < calres; i++) {
double vv = i/(calres-1.0);
@@ -448,6 +470,8 @@ static void xcal_interp(xcal *p, double *out, double *in) {
}
}
+#ifndef SALONEINSTLIB
+
#define MAX_INVSOLN 10 /* Rspl maximum reverse solutions */
/* Translate a value backwards through the curves. */
@@ -497,6 +521,8 @@ static int xcal_inv_interp(xcal *p, double *out, double *in) {
return rv;
}
+#endif /* !SALONEINSTLIB */
+
/* Translate a value through one of the curves */
static double xcal_interp_ch(xcal *p, int ch, double in) {
co tp;
@@ -509,6 +535,8 @@ static double xcal_interp_ch(xcal *p, int ch, double in) {
return tp.v[0];
}
+#ifndef SALONEINSTLIB
+
/* Translate a value backwards through one of the curves */
/* Return -1.0 if the inversion fails */
static double xcal_inv_interp_ch(xcal *p, int ch, double in) {
@@ -522,7 +550,7 @@ static double xcal_inv_interp_ch(xcal *p, int ch, double in) {
pp[0].v[0] = in;
- nsoln = p->cals[ch]->rev_interp (
+ nsoln = p->cals[ch]->rev_interp(
p->cals[ch], /* this */
RSPL_NEARCLIP, /* Clip to nearest (faster than vector) */
MAX_INVSOLN, /* Maximum number of solutions allowed for */
@@ -553,6 +581,8 @@ static double xcal_inv_interp_ch(xcal *p, int ch, double in) {
return pp[k].p[0];
}
+#endif /* !SALONEINSTLIB */
+
/* Delete an xcal */
static void xcal_del(xcal *p) {
int j;
@@ -583,14 +613,20 @@ xcal *new_xcal(void) {
/* Init method pointers */
p->del = xcal_del;
p->read_cgats = xcal_read_cgats;
+#ifndef SALONEINSTLIB
p->read_icc = xcal_read_icc;
+#endif /* !SALONEINSTLIB */
p->read = xcal_read;
p->write_cgats = xcal_write_cgats;
p->write = xcal_write;
p->interp = xcal_interp;
+#ifndef SALONEINSTLIB
p->inv_interp = xcal_inv_interp;
+#endif /* !SALONEINSTLIB */
p->interp_ch = xcal_interp_ch;
+#ifndef SALONEINSTLIB
p->inv_interp_ch = xcal_inv_interp_ch;
+#endif /* !SALONEINSTLIB */
return p;
}
diff --git a/xicc/xcal.h b/xicc/xcal.h
index f7c3fa9..c70b884 100644
--- a/xicc/xcal.h
+++ b/xicc/xcal.h
@@ -3,8 +3,11 @@
#define XCAL_H
/*
- * Argyll Color Correction System
* Calibration curve class.
+ */
+
+/*
+ * Argyll Color Correction System
*
* Author: Graeme W. Gill
* Date: 30/10/2005
@@ -20,6 +23,18 @@
* when computing ink limits.
*/
+#ifdef SALONEINSTLIB
+
+/* Sub-set of profile Creation Suplimental Information structure */
+struct _profxinf {
+ char *deviceMfgDesc; /* Manufacturer text description, NULL for none */
+ char *modelDesc; /* Model text description, NULL for none */
+ char *profDesc; /* Text profile description, NULL for default */
+ char *copyright; /* Copyrigh text, NULL for default */
+}; typedef struct _profxinf profxinf;
+
+#endif /* SALONEINSTLIB */
+
struct _xcal {
/* Public: */
@@ -29,9 +44,11 @@ struct _xcal {
/* Return nz if this fails (filename is for error messages) */
int (*read_cgats) (struct _xcal *p, cgats *cg, int table, char *filename);
+#ifndef SALONEINSTLIB
/* Read a calibration file from an ICC vcgt tag */
/* Return nz if this fails */
int (*read_icc) (struct _xcal *p, icc *c);
+#endif
/* Read a calibration file */
/* Return nz if this fails */
@@ -48,16 +65,20 @@ struct _xcal {
/* Translate values through the curves. */
void (*interp) (struct _xcal *p, double *out, double *in);
+#ifndef SALONEINSTLIB
/* Translate a value backwards through the curves. */
/* Return nz if the inversion fails */
int (*inv_interp) (struct _xcal *p, double *out, double *in);
+#endif
/* Translate a value through one of the curves */
double (*interp_ch) (struct _xcal *p, int ch, double in);
+#ifndef SALONEINSTLIB
/* Translate a value backwards through one of the curves */
/* Return -1.0 if the inversion fails */
double (*inv_interp_ch) (struct _xcal *p, int ch, double in);
+#endif
int noramdac; /* Set to nz if there was no VideoLUT access */
int tvenc; /* nz if this cal was created using (16-235)/255 Video encoding */
diff --git a/xicc/xcam.c b/xicc/xcam.c
index 6117cd1..0b46a24 100644
--- a/xicc/xcam.c
+++ b/xicc/xcam.c
@@ -24,7 +24,7 @@
static void icx_cam_free(icxcam *s);
static int icx_set_view(icxcam *s, ViewingCondition Ev, double Wxyz[3],
double La, double Yb, double Lv, double Yf, double Yg, double Gxyz[3],
- int hk);
+ int hk, double hkscale);
static int icx_XYZ_to_cam(struct _icxcam *s, double Jab[3], double XYZ[3]);
static int icx_cam_to_XYZ(struct _icxcam *s, double XYZ[3], double Jab[3]);
static void settrace(struct _icxcam *s, int tracev);
@@ -128,7 +128,8 @@ double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
double Yg, /* Glare as a fraction of the adapting/surround (Y range 0.0 .. 1.0) */
double Gxyz[3], /* The Glare white coordinates (typically the Ambient color) */
-int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+int hk, /* Flag, NZ to use Helmholtz-Kohlraush effect */
+double hkscale /* HK effect scaling factor */
) {
s->Wxyz[0] = Wxyz[0];
s->Wxyz[1] = Wxyz[1];
@@ -141,7 +142,7 @@ int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
}
case cam_CIECAM02: {
cam02 *pp = (cam02 *)s->p;
- return pp->set_view(pp, Ev, Wxyz, La, Yb, Lv, Yf, Yg, Gxyz, hk);
+ return pp->set_view(pp, Ev, Wxyz, La, Yb, Lv, Yf, Yg, Gxyz, hk, hkscale);
}
default:
break;
diff --git a/xicc/xcam.h b/xicc/xcam.h
index 021c621..de4f5b4 100644
--- a/xicc/xcam.h
+++ b/xicc/xcam.h
@@ -51,7 +51,8 @@ struct _icxcam {
double Yf, /* Flare as a fraction of the reference white (range 0.0 .. 1.0) */
double Yg, /* Glare as a fraction of the adapting/surround (range 0.0 .. 1.0) */
double Gxyz[3], /* The Glare white coordinates (typically the Ambient color) */
- int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+ int hk, /* Flag, NZ to use Helmholtz-Kohlraush effect */
+ double hkscale /* HK effect scaling factor */
);
/* Conversions */
diff --git a/xicc/xcolorants.c b/xicc/xcolorants.c
index 84a7720..edc7e52 100644
--- a/xicc/xcolorants.c
+++ b/xicc/xcolorants.c
@@ -2,7 +2,9 @@
/*
* International Color Consortium color transform expanded support
* Known colorants support.
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 24/2/2002
* Version: 1.00
@@ -24,7 +26,12 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#ifndef SALONEINSTLIB
#include "icc.h"
+#else
+#include "numsup.h"
+#include "sa_conv.h"
+#endif
#include "xcolorants.h"
#include "sort.h"
@@ -610,7 +617,6 @@ inkmask mask /* Colorant combination mask */
}
-
/* - - - - - - - - - - - - - - - - - */
/* Approximate device colorant model */
diff --git a/xicc/xcolorants.h b/xicc/xcolorants.h
index 460c4b0..e328ad2 100644
--- a/xicc/xcolorants.h
+++ b/xicc/xcolorants.h
@@ -3,7 +3,9 @@
/*
* International Color Consortium color transform expanded support
* Known colorant definitions.
- *
+ */
+
+/*
* Author: Graeme W. Gill
* Date: 24/2/2002
* Version: 1.00
@@ -45,7 +47,9 @@
Another change would be to make xcolorants an object,
with dynamic colorant and colorant combination values.
These would be initialised to defaults, but could then
- be added to at run time.
+ be added to at run time, to support import/export to
+ other color data formats, and coping with arbitrary raster
+ files etc.
Handling the "colorant" of non-device type color channels
is also a challenge (ie., Lab, Hsv etc.)
@@ -250,6 +254,8 @@ inkmask icx_enum_colorant_comb(int no, char **desc);
/* return NZ if it does. */
int icx_colorant_comb_match_icc(inkmask mask, icColorSpaceSignature sig);
+#ifndef SALONEINSTLIB
+
/* Given an ICC colorspace signature, return the appropriate */
/* colorant combination mask. Return 0 if ambiguous signature. */
inkmask icx_icc_to_colorant_comb(icColorSpaceSignature sig, icProfileClassSignature deviceClass);
@@ -265,6 +271,8 @@ inkmask icx_icc_cv_to_colorant_comb(icColorSpaceSignature sig, icProfileClassSig
/* return 0 if there is no match */
icColorSpaceSignature icx_colorant_comb_to_icc(inkmask mask);
+#endif /* !SALONEINSTLIB */
+
/* --------------------------------------------------------- */
/* An aproximate device colorant model object lookup object: */
diff --git a/xicc/xdevlin.c b/xicc/xdevlin.c
index a5f7bd6..05b4317 100644
--- a/xicc/xdevlin.c
+++ b/xicc/xdevlin.c
@@ -88,7 +88,7 @@ double *in /* di output */
pp[0].v[0] = in[i];
cdir = p->clipc[i] - in[i]; /* Clip towards output range */
- nsoln = p->curves[i]->rev_interp (
+ nsoln = p->curves[i]->rev_interp(
p->curves[i], /* this */
0, /* No flags */
MAX_INVSOLN, /* Maximum number of solutions allowed for */
diff --git a/xicc/xfbview.c b/xicc/xfbview.c
index affdb53..3d7c665 100644
--- a/xicc/xfbview.c
+++ b/xicc/xfbview.c
@@ -12,6 +12,9 @@
/* TTBD:
*
+ * Should reject device link profiles ?
+ *
+ *
*/
#include <stdio.h>
@@ -26,9 +29,13 @@
#include "icc.h"
#include "xicc.h"
#include "vrml.h"
-#include "ui.h"
-#define RW 0.5 /* Device Delta */
+#define RW 0.5 /* PCS Delta */
+
+//#define FLAGS ICX_CLIP_NEAREST | ICX_CAM_CLIP | ICX_FAST_SETUP
+//#define FLAGS ICX_CLIP_NEAREST | ICX_CAM_CLIP
+//#define FLAGS ICX_CLIP_NEAREST | ICX_FAST_SETUP
+#define FLAGS ICX_CLIP_NEAREST
/* - - - - - - - - - - - - - */
@@ -63,13 +70,13 @@ void usage(void) {
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
fprintf(stderr,"usage: fbtest [options] infile\n");
fprintf(stderr," -v verbose\n");
- fprintf(stderr," -f Show PCS target -> reference clipped PCS vectors\n");
- fprintf(stderr," -d Show PCS target -> average of device ref clippped PCS\n");
- fprintf(stderr," -b Show PCS target -> B2A lookup clipped PCS\n");
- fprintf(stderr," -e Show reference cliped PCS -> B2A lookup clipped PCS\n");
+ fprintf(stderr," -f Add PCS -inv(a2b)- device -a2b- PCS Vectors\n");
+ fprintf(stderr," -d Add ave(PCS + 4 x a*b* variations -inv(a2b)- device) -a2b- PCS\n");
+ fprintf(stderr," -b Add PCS -b2a- device -a2b- PCS Vectors\n");
+ fprintf(stderr," -e Add dif between inv(a2b) and b2a cliped vectors\n");
fprintf(stderr," -r res Resolution of test grid [Def 33]\n");
- fprintf(stderr," -g Do full grid, not just L = 0\n");
- fprintf(stderr," -c Do all values, not just clipped ones\n");
+ fprintf(stderr," -g Do full grid, not just cube\n");
+ fprintf(stderr," -a Do all values, not just clipped ones\n");
fprintf(stderr," -l tlimit set total ink limit, 0 - 400%% (estimate by default)\n");
fprintf(stderr," -L klimit set black ink limit, 0 - 100%% (estimate by default)\n");
exit(1);
@@ -90,7 +97,7 @@ main(
int dodelta = 0; /* Show device interp delta variation */
int dob2a = 0; /* Show B2A lookups */
int doeee = 0; /* Show clipped ref PCS to B2A clipped PCS */
- int dilzero = 1; /* Do just L = 0 plane */
+ int dogrid = 0; /* Do full grid, not just cube */
int doclip = 1; /* Do just clipped values */
char in_name[100];
char *xl, out_name[100];
@@ -98,6 +105,8 @@ main(
icc *rd_icco;
int rv = 0;
icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int inn; /* Number of device values */
+ double abscale = 128.0;
error_program = argv[0];
@@ -122,31 +131,31 @@ main(
}
/* Verbosity */
- if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ if (argv[fa][1] == 'v') {
verb = 1;
}
/* Show reference */
- else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ else if (argv[fa][1] == 'f') {
doref = 1;
}
/* Show device delta variation */
- else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ else if (argv[fa][1] == 'd') {
dodelta = 1;
}
/* Show B2A table lookup */
- else if (argv[fa][1] == 'b' || argv[fa][1] == 'B') {
+ else if (argv[fa][1] == 'b') {
dob2a = 1;
}
/* Show reference clipped PCS to clipped B2A PCS */
- else if (argv[fa][1] == 'e' || argv[fa][1] == 'E') {
+ else if (argv[fa][1] == 'e') {
doeee = 1;
}
- /* Do the full grid, not just L = 0 */
- else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') {
- dilzero = 0;
+ /* Do full grid, not just cube */
+ else if (argv[fa][1] == 'g') {
+ dogrid = 1;
}
/* Do all values, not just clipped ones */
- else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ else if (argv[fa][1] == 'a') {
doclip = 0;
}
/* Ink limit */
@@ -162,7 +171,7 @@ main(
}
/* Resolution */
- else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ else if (argv[fa][1] == 'r') {
fa = nfa;
if (na == NULL) usage();
tres = atoi(na);
@@ -241,15 +250,16 @@ main(
ink.c.Kshap = 1.0; /* Linear transition */
/* Get a Device to PCS conversion object */
- if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmFwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
- if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
+ if ((luo = xicco->get_luobj(xicco, FLAGS, icmFwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
+ if ((luo = xicco->get_luobj(xicco, FLAGS, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
error ("%d, %s",rd_icco->errc, rd_icco->err);
}
/* Get details of conversion */
- luo->spaces(luo, &ins, NULL, &outs, NULL, NULL, NULL, NULL, NULL);
+ luo->spaces(luo, &ins, &inn, &outs, NULL, NULL, NULL, NULL, NULL);
- if (ins != icSigCmykData) {
- error("Expecting CMYK device");
+ if (ins != icSigCmykData
+ && ins != icSigRgbData) {
+ error("Expecting RGB or CMYK device");
}
if ((wrl = new_vrml(out_name, doaxes, vrml_lab)) == NULL) {
@@ -258,17 +268,20 @@ main(
}
/* ---------------------------------------------- */
- /* The PCS target -> Reference clipped vectors */
+ /* Clipping vectors of inverse a2b */
+ /* PCS -inv(a2b)- device -a2b- PCS Vectors */
+ /* PCS -> device -> PCS */
if (doref) {
double rgb[3];
if (verb)
- printf("Doing PCS target to reference clipped PCS Vectors\n");
+ printf("Adding PCS -inv(a2b)- device -a2b- PCS Vectors \n");
wrl->start_line_set(wrl, 0);
i = 0;
+ /* For range of PCS values */
for (coa[0] = 0; coa[0] < tres; coa[0]++) {
for (coa[1] = 0; coa[1] < tres; coa[1]++) {
for (coa[2] = 0; coa[2] < tres; coa[2]++) {
@@ -276,14 +289,21 @@ main(
double temp[4];
int rv1, rv2;
+ if (!dogrid
+ && coa[0] != 0 && coa[0] != (tres-1)
+ && coa[1] != 0 && coa[1] != (tres-1)
+ && coa[2] != 0 && coa[2] != (tres-1)) {
+ continue;
+ }
+
temp[0] = coa[0]/(tres-1.0);
temp[1] = coa[1]/(tres-1.0);
temp[2] = coa[2]/(tres-1.0);
/* PCS values */
in[0] = temp[0] * 100.0;
- in[1] = 200.0 * temp[1] -100.0;
- in[2] = 200.0 * temp[2] -100.0;
+ in[1] = abscale * 2.0 * (temp[1] - 0.5);
+ in[2] = abscale * 2.0 * (temp[2] - 0.5);
/* Do reference lookup */
@@ -307,8 +327,6 @@ main(
i++;
}
}
- if (dilzero)
- break;
}
if (verb)
@@ -328,18 +346,19 @@ main(
}
/* ---------------------------------------------- */
- /* The Device Delta lines */
- /* The PCS target -> clipped from average of surrounding device values, vectors */
+ /* Clipping vectors of average around PCS of inverse a2b */
+ /* Average of(PCS + 4 x a*b* variations -inv(a2b)- device) -a2b- PCS */
if (dodelta) {
double rgb[3];
if (verb)
- printf("Doing target PCS to average of 4 surrounding device to PCS Vectors\n");
+ printf("Adding ave(PCS + 4 x a*b* variations -inv(a2b)- device) -a2b- PCS\n");
wrl->start_line_set(wrl, 0);
i = 0;
+ /* For Lab values */
for (coa[0] = 0; coa[0] < tres; coa[0]++) {
for (coa[1] = 0; coa[1] < tres; coa[1]++) {
for (coa[2] = 0; coa[2] < tres; coa[2]++) {
@@ -349,13 +368,22 @@ main(
double dev0[4], dev1[4], dev2[4], dev3[4];
int rv1, rv2;
+ if (!dogrid
+ && coa[0] != 0
+ && coa[0] != (tres-1)
+ && coa[1] != 0
+ && coa[1] != (tres-1)
+ && coa[2] != 0
+ && coa[2] != (tres-1))
+ continue;
+
temp[0] = coa[0]/(tres-1.0);
temp[1] = coa[1]/(tres-1.0);
temp[2] = coa[2]/(tres-1.0);
in[0] = temp[0] * 100.0;
- in[1] = 200.0 * temp[1] -100.0;
- in[2] = 200.0 * temp[2] -100.0;
+ in[1] = abscale * 2.0 * (temp[1] - 0.5);
+ in[2] = abscale * 2.0 * (temp[2] - 0.5);
/* Do reference lookup */
@@ -366,7 +394,7 @@ main(
if (doclip && rv2 != 1) /* Not clip */
continue;
- /* Device -> PCS check value */
+ /* Device -> PCS check value - not used */
if ((rv1 = luo->lookup(luo, check, dev)) > 1)
error ("%d, %s",rd_icco->errc,rd_icco->err);
@@ -377,8 +405,8 @@ main(
temp[2] = (coa[2]-RW)/(tres-1.0);
in4[0] = temp[0] * 100.0;
- in4[1] = 200.0 * temp[1] -100.0;
- in4[2] = 200.0 * temp[2] -100.0;
+ in4[1] = abscale * 2.0 * (temp[1] - 0.5);
+ in4[2] = abscale * 2.0 * (temp[2] - 0.5);
/* PCS -> Device */
if ((rv2 = luo->inv_lookup(luo, dev0, in4)) > 1)
@@ -394,8 +422,8 @@ main(
temp[2] = (coa[2]-RW)/(tres-1.0);
in4[0] = temp[0] * 100.0;
- in4[1] = 200.0 * temp[1] -100.0;
- in4[2] = 200.0 * temp[2] -100.0;
+ in4[1] = abscale * 2.0 * (temp[1] - 0.5);
+ in4[2] = abscale * 2.0 * (temp[2] - 0.5);
/* PCS -> Device */
if ((rv2 = luo->inv_lookup(luo, dev1, in4)) > 1)
@@ -411,8 +439,8 @@ main(
temp[2] = (coa[2]+RW)/(tres-1.0);
in4[0] = temp[0] * 100.0;
- in4[1] = 200.0 * temp[1] -100.0;
- in4[2] = 200.0 * temp[2] -100.0;
+ in4[1] = abscale * 2.0 * (temp[1] - 0.5);
+ in4[2] = abscale * 2.0 * (temp[2] - 0.5);
/* PCS -> Device */
if ((rv2 = luo->inv_lookup(luo, dev2, in4)) > 1)
@@ -428,8 +456,8 @@ main(
temp[2] = (coa[2]+RW)/(tres-1.0);
in4[0] = temp[0] * 100.0;
- in4[1] = 200.0 * temp[1] -100.0;
- in4[2] = 200.0 * temp[2] -100.0;
+ in4[1] = abscale * 2.0 * (temp[1] - 0.5);
+ in4[2] = abscale * 2.0 * (temp[2] - 0.5);
/* PCS -> Device */
if ((rv2 = luo->inv_lookup(luo, dev3, in4)) > 1)
@@ -440,7 +468,7 @@ main(
adev[2] += 0.25 * dev3[2];
adev[3] += 0.25 * dev3[3];
- /* Device -> PCS */
+ /* Average device -> PCS */
if ((rv1 = luo->lookup(luo, out, adev)) > 1)
error ("%d, %s",rd_icco->errc,rd_icco->err);
@@ -452,8 +480,6 @@ main(
i++;
}
}
- if (dilzero)
- break;
}
if (verb)
@@ -473,7 +499,8 @@ main(
}
/* ---------------------------------------------- */
- /* The target PCS -> clipped PCS using B2A table vectore */
+ /* Clipping vectors of b2a */
+ /* PCS -b2a- device -a2b- PCS Vectors */
if (dob2a) {
double rgb[3];
@@ -482,18 +509,19 @@ main(
wrl->start_line_set(wrl, 0);
- /* Get a PCS to Device conversion object */
- if ((luoB = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icAbsoluteColorimetric,
+ /* Get a B2A (PCS to Device) conversion object */
+ if ((luoB = xicco->get_luobj(xicco, FLAGS, icmBwd, icAbsoluteColorimetric,
icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
- if ((luoB = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icmDefaultIntent,
+ if ((luoB = xicco->get_luobj(xicco, FLAGS, icmBwd, icmDefaultIntent,
icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
error ("%d, %s",rd_icco->errc, rd_icco->err);
}
if (verb)
- printf("Doing target PCS to B2A clipped PCS Vectors\n");
+ printf("Adding PCS -b2a- device -a2b- PCS Vectors\n");
i = 0;
+ /* For PCS values */
for (coa[0] = 0; coa[0] < tres; coa[0]++) {
for (coa[1] = 0; coa[1] < tres; coa[1]++) {
for (coa[2] = 0; coa[2] < tres; coa[2]++) {
@@ -501,13 +529,22 @@ main(
double temp[4];
int rv1, rv2;
+ if (!dogrid
+ && coa[0] != 0
+ && coa[0] != (tres-1)
+ && coa[1] != 0
+ && coa[1] != (tres-1)
+ && coa[2] != 0
+ && coa[2] != (tres-1))
+ continue;
+
temp[0] = coa[0]/(tres-1.0);
temp[1] = coa[1]/(tres-1.0);
temp[2] = coa[2]/(tres-1.0);
in[0] = temp[0] * 100.0;
- in[1] = 200.0 * temp[1] -100.0;
- in[2] = 200.0 * temp[2] -100.0;
+ in[1] = abscale * 2.0 * (temp[1] - 0.5);
+ in[2] = abscale * 2.0 * (temp[2] - 0.5);
/* PCS -> Device */
if ((rv2 = luoB->lookup(luoB, dev, in)) > 1)
@@ -528,8 +565,6 @@ main(
i++;
}
}
- if (dilzero)
- break;
}
if (verb)
@@ -551,7 +586,11 @@ main(
}
/* ---------------------------------------------- */
- /* The reference clipped PCS -> B2A clipped PCS vectore */
+ /* Difference between:
+ PCS -inv(a2b)- device -a2b- PCS
+ and
+ PCS -b2a- device -a2b- PCS
+ */
if (doeee) {
double rgb[3];
@@ -561,15 +600,15 @@ main(
wrl->start_line_set(wrl, 0);
/* Get a PCS to Device conversion object */
- if ((luoB = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icAbsoluteColorimetric,
+ if ((luoB = xicco->get_luobj(xicco, FLAGS, icmBwd, icAbsoluteColorimetric,
icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
- if ((luoB = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icmDefaultIntent,
+ if ((luoB = xicco->get_luobj(xicco, FLAGS, icmBwd, icmDefaultIntent,
icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
error ("%d, %s",rd_icco->errc, rd_icco->err);
}
if (verb)
- printf("Doing reference clipped PCS to B2A table clipped PCS Vectors\n");
+ printf("Adding differenve between inv(a2b) and b2a cliped vectors\n");
i = 0;
for (coa[0] = 0; coa[0] < tres; coa[0]++) {
@@ -580,15 +619,24 @@ main(
double temp[4];
int rv1, rv2;
+ if (!dogrid
+ && coa[0] != 0
+ && coa[0] != (tres-1)
+ && coa[1] != 0
+ && coa[1] != (tres-1)
+ && coa[2] != 0
+ && coa[2] != (tres-1))
+ continue;
+
temp[0] = coa[0]/(tres-1.0);
temp[1] = coa[1]/(tres-1.0);
temp[2] = coa[2]/(tres-1.0);
in[0] = temp[0] * 100.0;
- in[1] = 200.0 * temp[1] -100.0;
- in[2] = 200.0 * temp[2] -100.0;
+ in[1] = abscale * 2.0 * (temp[1] - 0.5);
+ in[2] = abscale * 2.0 * (temp[2] - 0.5);
- /* Do reference lookup */
+ /* Do reference lookup using inverse a2b */
/* PCS -> Device */
if ((rv1 = luo->inv_lookup(luo, dev, in)) > 1)
error ("%d, %s",rd_icco->errc,rd_icco->err);
@@ -597,6 +645,7 @@ main(
if (luo->lookup(luo, check, dev) > 1)
error ("%d, %s",rd_icco->errc,rd_icco->err);
+
/* Do B2A table lookup */
/* PCS -> Device */
if ((rv2 = luoB->lookup(luoB, dev, in)) > 1)
@@ -617,8 +666,6 @@ main(
i++;
}
}
- if (dilzero)
- break;
}
if (verb)
diff --git a/xicc/xfit.c b/xicc/xfit.c
index d12919f..91afa64 100644
--- a/xicc/xfit.c
+++ b/xicc/xfit.c
@@ -1816,18 +1816,15 @@ static int xfit_fit(
icmAry2XYZ(_wp, p->wp);
- /* Absolute->Aprox. Relative Adaptation matrix */
- if (p->picc != NULL)
- p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, icmD50, _wp, p->fromAbs);
- else
- icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->fromAbs);
-
+ /* Absolute->Aprox. Relative Adaptation matrix and */
/* Aproximate relative to absolute conversion matrix */
- if (p->picc != NULL)
- p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, _wp, icmD50, p->toAbs);
- else
+ if (p->picc != NULL) {
+ p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, p->toAbs, p->fromAbs, icmD50, _wp);
+ } else {
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->fromAbs);
icmChromAdaptMatrix(ICM_CAM_BRADFORD, _wp, icmD50, p->toAbs);
-
+ }
+
if (p->verb) {
double lab[3];
icmXYZ2Lab(&icmD50, lab, p->wp);
@@ -2664,7 +2661,7 @@ printf("~1 ipos[%d][%d] = %f\n",e,i,cv);
/* Matrix needed to correct approx rel wp to target D50 */
icmAry2XYZ(_wp, wcc.v); /* Aprox relative target white point */
if (p->picc != NULL) /* Correction */
- p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, icmD50, _wp, p->cmat);
+ p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, NULL, p->cmat, icmD50, _wp);
else
icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->cmat);
@@ -2687,8 +2684,7 @@ printf("~1 ipos[%d][%d] = %f\n",e,i,cv);
/* Fix absolute conversions to leave absolute response unchanged. */
icmAry2XYZ(_wp, wp); /* Actual white point */
if (p->picc != NULL) {
- p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, icmD50, _wp, p->fromAbs);
- p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, _wp, icmD50, p->toAbs);
+ p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, p->toAbs, p->fromAbs, icmD50, _wp);
} else {
icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->fromAbs);
icmChromAdaptMatrix(ICM_CAM_BRADFORD, _wp, icmD50, p->toAbs);
diff --git a/xicc/xicc.c b/xicc/xicc.c
index 058f492..9e35ffc 100644
--- a/xicc/xicc.c
+++ b/xicc/xicc.c
@@ -902,6 +902,18 @@ xicc *p
free (p);
}
+/* return nz if the intent implies Jab space */
+int xiccIsIntentJab(icRenderingIntent intent) {
+
+ if (intent == icxAppearance
+ || intent == icxAbsAppearance
+ || intent == icxPerceptualAppearance
+ || intent == icxAbsPerceptualAppearance
+ || intent == icxSaturationAppearance
+ || intent == icxAbsSaturationAppearance)
+ return 1;
+ return 0;
+}
/* Return an expanded lookup object, initialised */
/* from the icc. */
@@ -934,12 +946,7 @@ icxInk *ink /* inking details (NULL for default) */
//printf("~1 xicc_get_luobj got intent '%s' and pcsor '%s'\n",icx2str(icmRenderingIntent,intent),icx2str(icmColorSpaceSignature,pcsor));
/* Ensure that appropriate PCS is slected for an appearance intent */
- if (intent == icxAppearance
- || intent == icxAbsAppearance
- || intent == icxPerceptualAppearance
- || intent == icxAbsPerceptualAppearance
- || intent == icxSaturationAppearance
- || intent == icxAbsSaturationAppearance) {
+ if (xiccIsIntentJab(intent)) {
pcsor = icxSigJabData;
//printf("~1 pcsor = %s\n",tag2str(pcsor));
@@ -1365,6 +1372,7 @@ icxViewCond *vc /* Viewing parameters to return */
printf("Technology = %s\n",tag2str(tsig));
printf("deviceClass = %s\n",tag2str(devc));
printf("Transparency = %d\n",trans);
+ // hk ? hkscale ?
#endif
/* See if the viewing conditions are completely defined as ICC can do it */
@@ -1625,7 +1633,7 @@ icxViewCond *vc, /* Viewing parameters to return, May be NULL if desc is nz */
int no, /* Enumeration to return, -1 for default, -2 for none */
char *as, /* String alias to number, NULL if none */
int desc, /* NZ - Just return a description of this enumeration in vc */
-double *wp /* Provide white point if xicc is NULL */
+double *wp /* Provide XYZ white point if xicc is NULL */
) {
if (desc == 0) { /* We're setting the viewing condition */
@@ -1665,6 +1673,9 @@ double *wp /* Provide white point if xicc is NULL */
vc->Gxyz[0] = vc->Wxyz[0];
vc->Gxyz[1] = vc->Wxyz[1];
vc->Gxyz[2] = vc->Wxyz[2];
+
+ /* Default HK scaling factor = none */
+ vc->hkscale = 1.0;
}
/*
@@ -1919,6 +1930,7 @@ icxViewCond *vc
printf(" Flare to image ratio = %f\n",vc->Yf);
printf(" Glare to adapting/surround ratio = %f\n",vc->Yg);
printf(" Flare color = %f %f %f\n",vc->Gxyz[0], vc->Gxyz[1], vc->Gxyz[2]);
+ printf(" HK scaling = %f\n",vc->hkscale);
}
@@ -1997,6 +2009,8 @@ char *as /* Alias string selector, NULL for none */
fprintf(stderr,"!!!!!! Warning, USE_CAM is off in xicc.c !!!!!!\n");
#endif
+ gmi->hkscale = -1.0; /* Default is to not override viewing condition HK factor */
+
/* Assert default if no guidance given */
if (no == icxNoGMIntent && as == NULL)
no = icxDefaultGMIntent;
@@ -2209,7 +2223,6 @@ char *as /* Alias string selector, NULL for none */
gmi->desc = "lp - Luminance Preserving Perceptual";
gmi->icci = icPerceptual;
gmi->usecas = perccas; /* Appearance space */
-// gmi->usecas = 0; /* Lab space */
gmi->usemap = 1; /* Use gamut mapping */
gmi->greymf = 1.0; /* Fully align grey axis */
gmi->glumwcpf = 1.0; /* Fully compress grey axis at white end */
@@ -2226,6 +2239,7 @@ char *as /* Alias string selector, NULL for none */
gmi->gamlpwf = 1.0; /* Full Linear Preserving Perceptual wghtg. factor */
gmi->gamswf = 0.0; /* No Saturation weighting factor */
gmi->satenh = 0.0; /* No saturation enhancement */
+ gmi->hkscale = 0.2; /* Mostly disable HK appearance modeling */
}
else if (no == 8
|| (as != NULL && stricmp(as,"ms") == 0)) {
@@ -2389,6 +2403,8 @@ icxGMappingIntent *gmi /* Gamut Mapping parameters to return */
printf(" Gamut Saturation mapping weighting factor %f\n", gmi->gamswf);
printf(" Saturation enhancement factor %f\n", gmi->satenh);
}
+ if (gmi->hkscale >= 0.0)
+ printf(" HK scale override %f\n", gmi->hkscale);
}
/* ------------------------------------------------------ */
diff --git a/xicc/xicc.h b/xicc/xicc.h
index a5ecf95..e4db20d 100644
--- a/xicc/xicc.h
+++ b/xicc/xicc.h
@@ -172,11 +172,10 @@ typedef struct {
/* Structure to convey inverse lookup clip handling details */
struct _icxClip {
int nearclip; /* Flag - use near clipping not vector */
- int LabLike; /* Flag Its an Lab like colorspace */
+ int LabLike; /* Flag It's an Lab like colorspace */
int fdi; /* Dimentionality of clip vector */
- double ocent[MXDO]; /* base of center of clut output gamut */
- double ocentv[MXDO]; /* vector direction of clut output clip target line */
- double ocentl; /* clip target line length */
+ struct _icxCuspMap *cm; /* Cusp map for computing vector (if !NULL) */
+ double ocent[MXDO]; /* Default center of clut output gamut used if cm == NULL */
}; typedef struct _icxClip icxClip;
/* Structure to convey viewing conditions */
@@ -191,6 +190,7 @@ typedef struct {
double Yg; /* Glare as a fraction of the adapting/surround (Y range 0.0 .. 1.0) */
double Gxyz[3]; /* The Glare white coordinates (ie the Ambient color) */
/* will be taken from Wxyz if Gxyz <= 0.0 */
+ double hkscale; /* [1.0] HK scaling factor */
char *desc; /* Possible description of this VC */
} icxViewCond;
@@ -227,6 +227,7 @@ typedef struct {
double gamlpwf; /* Gamut Lightness preserving perceptual Map whtg. factor, 0.0 - 1.0 */
double gamswf; /* Gamut Saturation Map weighting factor, 0.0 - 1.0 */
double satenh; /* Saturation enhancement value, 0.0 - Inf */
+ double hkscale; /* [1.0] Optional HK scaling factor */
char *as; /* Alias string (option name) */
char *desc; /* Possible description of this VC */
icRenderingIntent icci; /* Closest ICC intent */
@@ -431,6 +432,13 @@ xicc *new_xicc(icc *picc);
gamut * (*get_gamut) (struct _icxLuBase *plu, /* xicc lookup object */ \
double detail); /* gamut detail level, 0.0 = def */ \
\
+ /* Given an xicc lookup object, return an icxCuspMap object. */ \
+ /* Note that the PCS must be Lab or Jab. */ \
+ /* An icxLuLut type must be icmFwd, and the ink limit (if supplied) */ \
+ /* will be applied. */ \
+ /* Return NULL on error, check errc+err for reason */ \
+ struct _icxCuspMap *(*get_cuspmap)(struct _icxLuBase *p, int res); \
+ \
/* The following two functions expose the relative colorimetric native ICC PCS */ \
/* <--> absolute/CAM space transform, so that CAM based gamut compression */ \
/* can be applied in creating the ICC Lut tabls in profout.c. */ \
@@ -599,6 +607,10 @@ struct _icxLuLut {
/* ------------------------------------------------------------------------------ */
/* Utility declarations and functions */
+/* Utility that mirrors get_luobj intent handling: */
+/* return nz if the intent implies Jab space */
+int xiccIsIntentJab(icRenderingIntent intent);
+
/* Profile Creation Suplimental Information structure */
struct _profxinf {
icmSig manufacturer; /* Device manufacturer ICC Sig, 0 for default */
@@ -663,7 +675,7 @@ icxViewCond *vc, /* Viewing parameters to return, May be NULL if desc is nz */
int no, /* Enumeration to return, -1 for default, -2 for none */
char *as, /* String alias to number, NULL if none */
int desc, /* NZ - Just return a description of this enumeration in vc */
-double *wp /* Provide white point if xicc is NULL */
+double *wp /* Provide XYZ white point if xicc is NULL */
);
/* Debug: dump a Viewing Condition to standard out */
@@ -719,7 +731,8 @@ double icxMaxUnderlyingLimit(struct _xcal *cal, double ilimit);
double *icxClipVector(
icxClip *p, /* Clipping setup information */
double *in, /* Target point */
-double *cdirv /* Space for returned clip vector */
+double *cdirv, /* Returned clip vector */
+int safe /* Flag - return safe vector */
);
/* - - - - - - - - - - */
@@ -931,6 +944,28 @@ void icxdpdiMulBy3x3Parm(
/* - - - - - - - - - - */
+/* Cusp map - used for vector clipping in Lab like spaces */
+struct _icxCuspMap {
+ double Lmax[3]; /* Maximum L* value found */
+ double Lmin[3]; /* Minimum L* value found */
+ int res; /* Resolution of hue map */
+ double *L; /* L* value of cusp at hue angle */
+ double *C; /* C* value of cusp at hue angle */
+
+ /* Expand cusp map with given point */
+ void (*expand)(struct _icxCuspMap *p, double lab[3]);
+
+ /* Return the corresponding cusp location, given the source point */
+ void (*getCusp)(struct _icxCuspMap *p,double cuspLCh[3], double srcLab[3]);
+
+ /* We're done with CuspMap */
+ void (*del)(struct _icxCuspMap *p);
+
+}; typedef struct _icxCuspMap icxCuspMap;
+
+
+/* - - - - - - - - - - */
+
#include "xcal.h"
#endif /* XICC_H */
diff --git a/xicc/xicclu.c b/xicc/xicclu.c
index f8fb9d6..20c7d8b 100644
--- a/xicc/xicclu.c
+++ b/xicc/xicclu.c
@@ -40,7 +40,8 @@
#undef SPTEST /* Test rspl gamut surface code */
-#define USE_NEARCLIP /* Our usual expectation */
+#define USE_NEARCLIP /* [def] Our usual expectation */
+#define USE_FASTNNSETP /* [def] Make it more responsive */
#define XRES 128 /* Plotting resolution */
void usage(char *diag) {
@@ -54,10 +55,11 @@ void usage(char *diag) {
fprintf(stderr," -g Plot slice instead of looking colors up. (Default white to black)\n");
fprintf(stderr," -G s:L:a:b Override plot slice start with Lab or Jab co-ordinate \n");
fprintf(stderr," -G e:L:a:b Override plot slice end with Lab or Jab co-ordinate \n");
+ fprintf(stderr," -V Use 'vcgt' calibration tag from profile\n");
fprintf(stderr," -f function f = forward, b = backwards, g = gamut, p = preview\n");
fprintf(stderr," if = inverted forward, ib = inverted backwards\n");
fprintf(stderr," -i intent a = absolute, r = relative colorimetric\n");
- fprintf(stderr," p = perceptual, s = saturation\n");
+ fprintf(stderr," p = perceptual, s = saturation, A = disp. abs. measurements\n");
// fprintf(stderr," P = absolute perceptual, S = absolute saturation\n");
fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
@@ -151,6 +153,10 @@ void spioutf(void *cbntx, double *out, double *in) {
#endif /* SPTEST */
+#ifndef USE_FASTNNSETP
+#pragma message("!!!!!!!!!!!! USE_FASTNNSETP turned off !!!!!!!!!")
+#endif
+
int
main(int argc, char *argv[]) {
int fa, nfa, mfa; /* argument we're looking at */
@@ -159,6 +165,7 @@ main(int argc, char *argv[]) {
icc *icco = NULL;
xicc *xicco = NULL;
xcal *cal = NULL; /* If .cal rather than .icm/.icc, not NULL */
+ int dovcgt = 0; /* Extract cal out of icc profile */
int doplot = 0; /* Do grey axis plot */
double pstart[3] = { -1000.0 }; /* Plot Lab/Jab PCS start point = white */
double pend[3] = { -1000.0 }; /* Plot Lab/Jab PCS end point = black */
@@ -202,6 +209,8 @@ main(int argc, char *argv[]) {
/* Lookup parameters */
icmLookupFunc func = icmFwd; /* Default */
icRenderingIntent intent = icmDefaultIntent; /* Default */
+ int absmeas = 0; /* Show display absolute measurement in XYZ */
+ double dispLuminance = -1.0; /* Luminance value for absmeas */
icColorSpaceSignature pcsor = icmSigDefaultData; /* Default */
icmLookupOrder order = icmLuOrdNorm; /* Default */
int inking = 3; /* Default is ramp */
@@ -262,6 +271,11 @@ main(int argc, char *argv[]) {
}
}
+ /* Load ICC 'vcgt' tag as Cal */
+ else if (argv[fa][1] == 'V') {
+ dovcgt = 1;
+ }
+
/* Locus plot */
else if (argv[fa][1] == 'g') {
doplot = 1;
@@ -383,6 +397,7 @@ main(int argc, char *argv[]) {
else if (argv[fa][1] == 'i') {
if (na == NULL) usage("No parameter after flag -i");
fa = nfa;
+ absmeas = 0;
switch (na[0]) {
case 'p':
intent = icPerceptual;
@@ -396,6 +411,10 @@ main(int argc, char *argv[]) {
case 'a':
intent = icAbsoluteColorimetric;
break;
+ case 'A':
+ intent = icAbsoluteColorimetric;
+ absmeas = 1;
+ break;
/* Argyll special intents to check spaces underlying */
/* icxPerceptualAppearance & icxSaturationAppearance */
case 'P':
@@ -415,6 +434,7 @@ main(int argc, char *argv[]) {
fa = nfa;
switch (na[0]) {
case 'x':
+ /* (See also absmeas after options) */
pcsor = icSigXYZData;
repYxy = 0;
repLCh = 0;
@@ -676,6 +696,15 @@ main(int argc, char *argv[]) {
error("chrom_locus_poligon failed");
}
+ /* Force to XYZ PCS */
+ if (absmeas) {
+ pcsor = icSigXYZData;
+ repYxy = 0;
+ repLCh = 0;
+ repJCh = 0;
+ repXYZ100 = 0;
+ }
+
/* Open up the profile for reading */
if ((fp = new_icmFileStd_name(prof_name,"r")) == NULL)
error ("Can't open file '%s'",prof_name);
@@ -683,7 +712,26 @@ main(int argc, char *argv[]) {
if ((icco = new_icc()) == NULL)
error ("Creation of ICC object failed");
- if ((rv = icco->read(icco,fp,0)) == 0) { /* ICC profile */
+ if (dovcgt) {
+ if ((rv = icco->read(icco,fp,0)) != 0)
+ error ("Can't load ICC file '%s'",prof_name);
+
+ if ((cal = new_xcal()) == NULL)
+ error("new_xcal failed");
+
+ if ((cal->read_icc(cal, icco)) != 0) {
+ error ("ICC file '%s' doesn't contain a 'vcgt' tag",prof_name);
+ }
+
+ icco->del(icco);
+ fp->del(fp);
+ fp = NULL;
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ outs = ins = cal->colspace;
+ outn = inn = cal->devchan;
+
+ } else if ((rv = icco->read(icco,fp,0)) == 0) { /* ICC profile */
if (doplot) {
@@ -838,7 +886,9 @@ main(int argc, char *argv[]) {
| (intsep ? ICX_INT_SEPARATE : 0)
| (merge ? ICX_MERGE_CLUT : 0)
| (camclip ? ICX_CAM_CLIP : 0)
+#ifdef USE_FASTNNSETP
| ICX_FAST_SETUP
+#endif
, func, intent, pcsor, order, &vc, &ink)) == NULL)
error ("%d, %s",xicco->errc, xicco->err);
@@ -937,7 +987,23 @@ main(int argc, char *argv[]) {
}
#endif
+ /* If we are doing display absolute measurement PCS */
+ if (absmeas) {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)icco->read_tag(
+ icco, icSigLuminanceTag)) != NULL
+ && wo->ttype == icSigXYZArrayType) {
+ dispLuminance = wo->data[0].Y;
+ }
+ if (verb)
+ printf("Display Luminance = %f cd/m^2\n", dispLuminance);
+
+ if (dispLuminance <= 0.0)
+ error("Unable to read display luminance tag from '%s'\n",prof_name);
+ }
+
} else { /* See if it's a .cal */
+ icco->del(icco);
fp->del(fp);
fp = NULL;
@@ -953,6 +1019,11 @@ main(int argc, char *argv[]) {
outn = inn = cal->devchan;
}
+ /* Sanity check */
+ if (absmeas && ins != icSigXYZData && outs != icSigXYZData) {
+ error("Must be XYZ PCS space for display absolute measurement");
+ }
+
if (verb > 1 && icco != NULL) {
icmFile *op;
if ((op = new_icmFileStd_fp(stdout)) == NULL)
@@ -1147,6 +1218,13 @@ main(int argc, char *argv[]) {
in[2] = C * sin(3.14159265359/180.0 * h);
}
+ /* display absolute measurement */
+ if (absmeas && ins == icSigXYZData) {
+ in[0] /= dispLuminance;
+ in[1] /= dispLuminance;
+ in[2] /= dispLuminance;
+ }
+
/* Do conversion */
if (cal != NULL) { /* .cal */
if (func == icmBwd || invert) {
@@ -1184,6 +1262,13 @@ main(int argc, char *argv[]) {
for (i = 0; i < MAX_CHAN; i++)
uout[i] = out[i];
+ /* display absolute measurement */
+ if (absmeas && outs == icSigXYZData) {
+ uout[0] *= dispLuminance;
+ uout[1] *= dispLuminance;
+ uout[2] *= dispLuminance;
+ }
+
if (repXYZ100 && outs == icSigXYZData) {
uout[0] *= 100.0;
uout[1] *= 100.0;
diff --git a/xicc/xlut.c b/xicc/xlut.c
index 827dde8..a18956c 100644
--- a/xicc/xlut.c
+++ b/xicc/xlut.c
@@ -54,7 +54,7 @@
/*
- ~~~~~!!!!! This has all been fixed ?
+ !!!!! This has all been fixed ? !!!!!!
NOTE :- an alternative to the way display profile absolute is handled here
would be to always chromatically adapt the illuminant to D50, and encode
@@ -160,6 +160,9 @@
#undef DISABLE_KCURVE_FILTER /* [Undef] don't filter the Kcurve */
#undef REPORT_LOCUS_SEGMENTS /* [Undef[ Examine how many segments there are in aux inversion */
+#undef FASTREVSETUP_NON_CAM /* [Undef] Use fast setup on innerm non-CAM lookup, if we're */
+ /* going to use CAM clip for nn lookup */
+
#define XYZ_EXTRA_SMOOTH 20.0 /* Extra smoothing factor for XYZ profiles */
/* !!! Note this is mainly due to smoothing being */
/* scaled by data range in rspl code !!! */
@@ -171,7 +174,10 @@
/* Should this be smaller ? */
#undef USECAMCLIPSPLINE /* [Und] use spline blend between PCS and Jab */
-#define CCJSCALE 2.0 /* [2.0] Amount to emphasize J delta E in in computing clip */
+#define USELCHWEIGHT /* [def] Use LCh weighting for nn clip if possible */
+#define JCCWEIGHT 2.0 /* [2.0] Amount to emphasize J delta E in in computing clip */
+#define CCCWEIGHT 1.0 /* [1.0] Amount to emphasize C delta E in in computing clip */
+#define HCCWEIGHT 2.2 /* [2.2] Amount to emphasize H delta E in in computing clip */
/*
* TTBD:
@@ -429,7 +435,6 @@ icColorSpaceSignature is, /* Input space, XYZ or Lab */
double *out, double *in) {
icxLuLut *p = (icxLuLut *)pp;
-
/* Convert to the ICC PCS */
if (is == icSigLabData && p->natpcs == icSigXYZData) {
DBS(("fwd_relpcs_outpcs: Lab in = %s\n", icmPdv(p->inputChan, in)));
@@ -444,7 +449,7 @@ double *out, double *in) {
icmCpy3(out, in);
}
- /* Convert to absolute */
+ /* Convert to final PCS (i.e. absolute intent is set that way) */
((icmLuLut *)p->plu)->out_abs((icmLuLut *)p->plu, out, out);
DBS(("fwd_relpcs_outpcs: abs PCS = %s\n", icmPdv(p->inputChan, out)));
@@ -461,51 +466,98 @@ double *out, double *in) {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Components of inverse lookup, in order */
+static double sigfunc(double in, double pp) {
+ if (in < 0.5)
+ return pow(2 * in, pp) * 0.5;
+ else
+ return 1.0 - (pow(2 * (1.0 - in), pp) * 0.5);
+}
+
/* Utility function - compute the clip vector direction. */
/* return NULL if vector clip isn't used. */
double *icxClipVector(
icxClip *p, /* Clipping setup information */
double *in, /* Target point */
-double *cdirv /* Space for returned clip vector */
+double *cdirv, /* Returned clip vector */
+int safe /* Flag - return safe vector */
) {
int f;
if (p->nearclip != 0)
return NULL; /* Doing nearest clipping, not vector */
- /* Default is simple vector clip */
- for (f = 0; f < p->fdi; f++)
- cdirv[f] = p->ocent[f] - in[f]; /* Clip towards output gamut center */
+ if (p->cm == NULL) {
+ /* Default is simple vector clip */
+ for (f = 0; f < p->fdi; f++)
+ cdirv[f] = p->ocent[f] - in[f]; /* Clip towards output gamut center */
+
+ /* Else use CuspMap for more targeted vector */
+ } else {
+ double Cpow = 2.0; /* [2.0] 4.0 for less L change */
+ double Lsig = 2.5; /* [2.5] 1.6 for less L change */
+ double Lpow = 0.5; /* [0.5] 0.8 for less L change */
+ double Cratio = 0.9; /* [0.9] see cusptest.c */
+ double ratio;
+ double ss[3];
+ double inC;
+ double targ[3], cuspLCh[3];
- if (p->ocentl != 0.0) { /* Graduated vector clip */
- double cvl, nll;
+ inC = sqrt(in[1] * in[1] + in[2] * in[2]);
- /* Compute (negative) clip vector length */
- for (cvl = 0.0, f = 0; f < p->fdi; f++) {
- cvl += cdirv[f] * cdirv[f];
+ p->cm->getCusp(p->cm, cuspLCh, in);
+
+
+//icmLCh2Lab(targ, cuspLCh);
+//printf("\n~1 in %f %f %f -> cusp %f %f %f\n", in[0], in[1], in[2], targ[0], targ[1], targ[2]);
+//printf("~1 in %f %f %f -> cuspLCh %f %f %f\n", in[0], in[1], in[2], cuspLCh[0], cuspLCh[1], cuspLCh[2]);
+
+ /* Constrain clip vector to always be inwards pointing */
+ if (cuspLCh[1] > 0.90 * inC) {
+ cuspLCh[1] = 0.90 * inC;
+//printf("~1 Constrain cusp C: cuspLCh %f %f %f\n", cuspLCh[0], cuspLCh[1], cuspLCh[2]);
}
- cvl = sqrt(cvl);
- if (cvl > 1e-8) {
- /* Dot product of clip vector and clip center line */
- for (nll = 0.0, f = 0; f < p->fdi; f++)
- nll -= cdirv[f] * p->ocentv[f]; /* (Fix -ve clip vector) */
- nll /= (p->ocentl * p->ocentl); /* Normalised location along line */
-
- /* Limit to line */
- if (nll < 0.0)
- nll = 0.0;
- else if (nll > 1.0)
- nll = 1.0;
-
- if (p->LabLike) {
- /* Aim more towards center for saturated targets */
- double sat = sqrt(in[1] * in[1] + in[2] * in[2]);
- nll += sat/150.0 * (0.5 - nll);
- }
- /* Compute target clip direction */
- for (f = 0; f < p->fdi; f++)
- cdirv[f] = p->ocent[f] + nll * p->ocentv[f] - in[f];
+ ss[0] = in[0];
+ ss[1] = in[1];
+ ss[2] = in[2];
+
+ if (ss[0] < p->cm->Lmin[0])
+ ss[0] = p->cm->Lmin[0];
+ if (ss[0] > p->cm->Lmax[0])
+ ss[0] = p->cm->Lmax[0];
+
+ if (safe) {
+ targ[0] = cuspLCh[0]; /* L target is cusp L */
+ targ[1] = 0.0; /* Right on the neutral axis */
+
+ } else {
+ if (ss[0] >= cuspLCh[0]) {
+ ratio = (p->cm->Lmax[0] - ss[0])/(p->cm->Lmax[0] - cuspLCh[0]);
+ targ[0] = p->cm->Lmax[0] - sigfunc(pow(ratio, Lpow), Lsig)
+ * (p->cm->Lmax[0] - cuspLCh[0]);
+ targ[1] = pow(ratio, Cpow) * Cratio * cuspLCh[1];
+ } else {
+ ratio = (ss[0] - p->cm->Lmin[0])/(cuspLCh[0] - p->cm->Lmin[0]);
+ targ[0] = p->cm->Lmin[0] + sigfunc(pow(ratio, Lpow), Lsig)
+ * (cuspLCh[0] - p->cm->Lmin[0]);
+ targ[1] = pow(ratio, Cpow) * Cratio * cuspLCh[1];
+ }
}
+ targ[2] = cuspLCh[2]; /* h of in */
+
+//printf("~1 targLCH %f %f %f\n", targ[0], targ[1], targ[2]);
+ icmLCh2Lab(targ, targ);
+//printf("~1 targ %f %f %f\n", targ[0], targ[1], targ[2]);
+
+ /* line target point up with white and black point ? */
+ ratio = (ss[0] - p->cm->Lmin[0])/(p->cm->Lmax[0] - p->cm->Lmin[0]);
+ targ[1] += (1.0 - ratio) * p->cm->Lmin[1] + ratio * p->cm->Lmax[1];
+ targ[2] += (1.0 - ratio) * p->cm->Lmin[2] + ratio * p->cm->Lmax[2];
+
+//printf("~1 in %f %f %f -> targ %f %f %f\n", in[0], in[1], in[2], targ[0], targ[1], targ[2]);
+
+ /* Compute target clip direction */
+ for (f = 0; f < p->fdi; f++)
+ cdirv[f] = (targ[f] - in[f]);
}
return cdirv;
@@ -855,7 +907,7 @@ static double icxKcurveNF(double L, icxInkCurve *c) {
#define DBK(xxx)
#endif
-/* Same as above, but implement transition filters accross inflection points. */
+/* Same as above, but implement transition filters across inflection points. */
/* (The convolultion filter previously used could be */
/* re-instituted if something was done about compressing */
/* the filter at the boundaries so that the levels are met.) */
@@ -999,12 +1051,14 @@ double *clipd, /* If not NULL, return DE to gamut on clipi, 0 for not clip */
double *in /* Function input values to invert (== clut output' values) */
) {
co pp[MAX_INVSOLN]; /* Room for all the solutions found */
+ co upp; /* pp[0] value sent to rev_interp() for replay. */
int nsoln; /* Number of solutions found */
- double *cdir, cdirv[MXDO]; /* Clip vector direction and length */
+ double *cdir, cdirv[MXDO]; /* Clip vector direction and length/LCh weighting */
int e,f,i;
int fdi = p->clutTable->fdi;
int flags = 0; /* reverse interp flags */
int xflags = 0; /* extra clip/noclip flags */
+ int uflags = 0; /* flags value sent to rev_interp() for replay */
double tin[MXDO]; /* PCS value to be inverted */
double cdist = 0.0; /* clip DE */
int crv = 0; /* Return value - set to 1 if clipped */
@@ -1026,10 +1080,10 @@ double *in /* Function input values to invert (== clut output' values) */
/* Setup for reverse lookup */
for (f = 0; f < fdi; f++)
- pp[0].v[f] = in[f]; /* Target value */
+ upp.v[f] = pp[0].v[f] = in[f]; /* Target value */
/* Compute clip vector, if any */
- cdir = icxClipVector(&p->clip, in, cdirv);
+ cdir = icxClipVector(&p->clip, in, cdirv, 0);
if (p->clutTable->di > fdi) { /* ie. CMYK->Lab, there will be ambiguity */
double min[MXDI], max[MXDI]; /* Auxiliary locus range */
@@ -1084,7 +1138,7 @@ double *in /* Function input values to invert (== clut output' values) */
/* even though it won't have any effect. */
for (e = 0; e < p->clutTable->di; e++) {
if (p->auxm[e] != 0) {
- pp[0].p[e] = 0.5;
+ upp.p[e] = pp[0].p[e] = 0.5;
}
}
@@ -1123,7 +1177,7 @@ double *in /* Function input values to invert (== clut output' values) */
iv = min[e];
else if (iv > max[e])
iv = max[e];
- pp[0].p[e] = iv;
+ upp.p[e] = pp[0].p[e] = iv;
}
}
DBR(("inv_clut_aux: aux %f from auxt[] %f\n",pp[0].p[3],auxt[0]))
@@ -1137,7 +1191,7 @@ double *in /* Function input values to invert (== clut output' values) */
iv = min[e];
else if (iv > max[e])
iv = max[e];
- pp[0].p[e] = iv;
+ upp.p[e] = pp[0].p[e] = iv;
}
}
DBR(("inv_clut_aux: aux %f from out[0] K target %f min %f max %f\n",pp[0].p[3],out[3],min[3],max[3]))
@@ -1152,7 +1206,7 @@ double *in /* Function input values to invert (== clut output' values) */
iv = min[e];
else if (iv > max[e])
iv = max[e];
- pp[0].p[e] = iv;
+ upp.p[e] = pp[0].p[e] = iv;
}
}
DBR(("inv_clut_aux: aux %f from out[0] locus %f min %f max %f\n",pp[0].p[3],out[3],min[3],max[3]))
@@ -1195,7 +1249,7 @@ double *in /* Function input values to invert (== clut output' values) */
for (e = 0; e < p->clutTable->di; e++) {
if (p->auxm[e] != 0) {
- pp[0].p[e] = min[e] + rv * (max[e] - min[e]);
+ upp.p[e] = pp[0].p[e] = min[e] + rv * (max[e] - min[e]);
}
}
DBR(("inv_clut_aux: aux %f from locus %f min %f max %f\n",pp[0].p[3],rv,min[3],max[3]))
@@ -1209,7 +1263,7 @@ double *in /* Function input values to invert (== clut output' values) */
iv = min[e];
else if (iv > max[e])
iv = max[e];
- pp[0].p[e] = iv;
+ upp.p[e] = pp[0].p[e] = iv;
}
}
DBR(("inv_clut_aux: aux %f from out[0] K target %f min %f max %f\n",pp[0].p[3],rv,min[3],max[3]))
@@ -1241,7 +1295,7 @@ double *in /* Function input values to invert (== clut output' values) */
ii = 1.0;
ii = (1.0 - ii) * rv + ii * rv2;/* Blend between locus rule curves */
/* Out ink from output locus */
- pp[0].p[e] = min[e] + ii * (max[e] - min[e]);
+ upp.p[e] = pp[0].p[e] = min[e] + ii * (max[e] - min[e]);
} else {
double iv;
iv = out[e]; /* Input K level */
@@ -1249,7 +1303,7 @@ double *in /* Function input values to invert (== clut output' values) */
iv = rv;
else if (iv > rv2)
iv = rv2;
- pp[0].p[e] = iv;
+ upp.p[e] = pp[0].p[e] = iv;
}
}
}
@@ -1270,7 +1324,7 @@ double *in /* Function input values to invert (== clut output' values) */
tv = max[e];
tc.p[0] = tv;
p->inputTable[e]->interp(p->inputTable[e], &tc);
- pp[0].p[e] = tc.v[0];
+ upp.p[e] = pp[0].p[e] = tc.v[0];
}
}
@@ -1291,16 +1345,18 @@ double *in /* Function input values to invert (== clut output' values) */
tin[f] = pp[0].v[f];
}
+ uflags = RSPL_MAXAUX | flags | xflags; /* Combine all the flags */
+
/* Find reverse solution with target auxiliaries */
/* We choose the closest aux at or above the target */
/* to try and avoid glitches near black due to */
/* possible forked black locuses. */
nsoln = p->clutTable->rev_interp(
p->clutTable, /* rspl object */
- RSPL_MAXAUX | flags | xflags, /* Combine all the flags */
+ uflags,
MAX_INVSOLN, /* Maxumum solutions to return */
p->auxm, /* Auxiliary input chanel mask */
- cdir, /* Clip vector direction and length */
+ cdir, /* Clip vector direction/LCh weighting */
pp); /* Input target and output solutions */
/* returned solutions in pp[0..retval-1].p[] */
@@ -1312,13 +1368,15 @@ double *in /* Function input values to invert (== clut output' values) */
tin[f] = pp[0].v[f];
}
+ uflags = flags; /* No extra flags */
+
/* Color spaces don't need auxiliaries to choose from solution locus */
nsoln = p->clutTable->rev_interp(
p->clutTable, /* rspl object */
- flags, /* No extra flags */
+ uflags,
MAX_INVSOLN, /* Maxumum solutions to return */
NULL, /* No auxiliary input targets */
- cdir, /* Clip vector direction and length */
+ cdir, /* Clip vector direction/LCh weighting */
pp); /* Input target and output solutions */
/* returned solutions in pp[0..retval-1].p[] */
}
@@ -1343,8 +1401,9 @@ double *in /* Function input values to invert (== clut output' values) */
DBR(("inv_clut_aux got %d rev_interp solutions, clipflag = %d\n",nsoln,crv))
/* If we clipped and we should clip in CAM Jab space, compute reverse */
- /* clip solution using our additional CAM space. */
- /* (Note that we don't support vector clip in CAM space at the moment) */
+ /* clip solution using our additional CAM space rspl. */
+ /* Note that we don't support vector clip in CAM space at the moment */
+ /* - icxLuLut_init_clut_camclip() doesn't setup CAM rspl for vector clip. */
if (crv != 0 && p->camclip && p->nearclip) {
co cpp; /* Alternate CAM space solution */
double bf; /* Blend factor */
@@ -1375,7 +1434,6 @@ double *in /* Function input values to invert (== clut output' values) */
for (f = 0; f < fdi; f++) /* Transfer CAM targ */
cpp.v[f] = tin[f];
- cpp.v[0] *= CCJSCALE;
/* Make sure that the auxiliar value is initialized, */
/* even though it shouldn't have any effect, since should clipp. */
@@ -1391,7 +1449,7 @@ double *in /* Function input values to invert (== clut output' values) */
flags | xflags | RSPL_WILLCLIP, /* Combine all the flags + clip ?? */
1, /* Maximum solutions to return */
p->auxm, /* Auxiliary input chanel mask */
- cdir, /* Clip vector direction and length */
+ cdir, /* Clip vector direction/ LCh weighting */
&cpp); /* Input target and output solutions */
} else {
@@ -1400,7 +1458,7 @@ double *in /* Function input values to invert (== clut output' values) */
flags | RSPL_WILLCLIP, /* Because we know it will clip ?? */
1, /* Maximum solutions to return */
NULL, /* No auxiliary input targets */
- cdir, /* Clip vector direction and length */
+ cdir, /* Clip vector direction/LCh weighting */
&cpp); /* Input target and output solutions */
}
@@ -1411,7 +1469,6 @@ double *in /* Function input values to invert (== clut output' values) */
}
/* Compute the CAM clip distances */
- cpp.v[0] /= CCJSCALE;
for (cdist = 0.0, f = 0; f < fdi; f++) {
double tt;
tt = cpp.v[f] - tin[f];
@@ -1453,12 +1510,59 @@ double *in /* Function input values to invert (== clut output' values) */
/* Not CAM clip case */
} else {
+ /* If vector clip, replay with simple vector */
+ if (nsoln == 0 && p->nearclip == 0) {
+//printf("~1 !!!!!!!!!!!!!! Vector clip failed - trying safe replay !!!!!!!!!!!!!!!1\n");
+
+ // Reset pp[0] target values and auiliaries
+ for (e = 0; e < p->clutTable->di; e++)
+ pp[0].p[e] = upp.p[e];
+ for (f = 0; f < fdi; f++)
+ pp[0].v[f] = upp.v[f];
+
+ /* Compute safe clip vector */
+ cdir = icxClipVector(&p->clip, in, cdirv, 1);
+
+ /* Replay the lookup using safer vector */
+ nsoln = p->clutTable->rev_interp(
+ p->clutTable, /* rspl object */
+ uflags,
+ MAX_INVSOLN, /* Maxumum solutions to return */
+ NULL, /* No auxiliary input targets */
+ cdir, /* Clip vector direction and length */
+ pp); /* Input target and output solutions */
+ /* returned solutions in pp[0..retval-1].p[] */
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln == 0) { /* Hmm */
+//printf("~1 !!!!!!!!!!!!!! Vector clip failed again - using nn replay !!!!!!!!!!!!!!!1\n");
+ // Reset pp[0] target values and auiliaries
+ for (e = 0; e < p->clutTable->di; e++)
+ pp[0].p[e] = upp.p[e];
+ for (f = 0; f < fdi; f++)
+ pp[0].v[f] = upp.v[f];
+
+ /* Replay the lookup as a nearclip, to guarantee a solution */
+ nsoln = p->clutTable->rev_interp(
+ p->clutTable, /* rspl object */
+ RSPL_NEARCLIP | RSPL_NONNSETUP,
+ MAX_INVSOLN, /* Maxumum solutions to return */
+ NULL, /* No auxiliary input targets */
+ NULL, /* No LCh weighting */
+ pp); /* Input target and output solutions */
+ /* returned solutions in pp[0..retval-1].p[] */
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+ }
+ }
+
if (nsoln == 1) { /* Exactly one solution */
i = 0;
} else if (nsoln == 0) { /* Zero solutions. This is unexpected. */
double in_v[MXDO];
p->output(p, in_v, pp[0].v); /* Get ICC inverse input values */
p->out_abs(p, in_v, in_v);
+ if (p->nearclip == 0)
+ a1logd(g_log,0,"Clip dst %f %f %f\n",pp[0].v[0]+cdir[0], pp[0].v[1]+cdir[1], pp[0].v[2]+cdir[2]);
error("Unexpected failure to find reverse solution for input to output table for value %f %f %f (ICC input %f %f %f)",pp[0].v[0],pp[0].v[1],pp[0].v[2], in_v[0], in_v[1], in_v[2]);
return 2;
} else { /* Multiple solutions */
@@ -1625,21 +1729,22 @@ int icxLuLut_inv_input(icxLuLut *p, double *out, double *in) {
int i,j;
int nsoln; /* Number of solutions found */
co pp[MAX_INVSOLN]; /* Room for all the solutions found */
- double cdir;
+// double cdir;
DBR(("inv_input got DEV' %f %f %f %f\n",in[0],in[1],in[2],in[3]))
for (i = 0; i < p->inputChan; i++) {
pp[0].p[0] = p->inputClipc[i];
pp[0].v[0] = in[i];
- cdir = p->inputClipc[i] - in[i]; /* Clip towards output range */
+// cdir = p->inputClipc[i] - in[i]; /* Clip towards output range */
nsoln = p->inputTable[i]->rev_interp (
p->inputTable[i], /* this */
RSPL_NEARCLIP, /* Clip to nearest (faster than vector) */
MAX_INVSOLN, /* Maximum number of solutions allowed for */
NULL, /* No auxiliary input targets */
- &cdir, /* Clip vector direction and length */
+ NULL, /* No LCH weight because this is 1D */
+// &cdir, /* Clip vector direction and length */
pp); /* Input and output values */
if (nsoln & RSPL_DIDCLIP)
@@ -1837,6 +1942,7 @@ icxLuBase *pp
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
static gamut *icxLuLutGamut(icxLuBase *plu, double detail);
+static icxCuspMap *icxLuLutCuspMap(icxLuBase *plu, int res);
/* Do the basic icxLuLut creation and initialisation */
static icxLuLut *
@@ -1860,6 +1966,7 @@ alloc_icxLuLut(
p->get_ranges = icxLu_get_ranges;
p->efv_wh_bk_points = icxLuEfv_wh_bk_points;
p->get_gamut = icxLuLutGamut;
+ p->get_cuspmap = icxLuLutCuspMap;
p->fwd_relpcs_outpcs = icxLuLut_fwd_relpcs_outpcs;
p->bwd_outpcs_relpcs = icxLuLut_bwd_outpcs_relpcs;
p->nearclip = 0; /* Set flag defaults */
@@ -2077,14 +2184,8 @@ icxLuLut *p /* Object being initialised */
p->clip.nearclip = 1;
} else { /* Vector clip */
- /* !!!! NOTE NOTE NOTE !!!! */
- /* We should re-write this to avoid calling p->clutTable->rev_interp(), */
- /* since this sets up all the rev acceleration tables for two calls, */
- /* if this lut is being setup from scattered data, and never used */
- /* for rev lookup */
icColorSpaceSignature clutos = p->natos;
- fprintf(stderr, "!!!!! setup_clip_icxLuLut with vector clip - possibly unnecessary rev setup !!!!\n");
p->clip.nearclip = 0;
p->clip.LabLike = 0;
p->clip.fdi = p->clutTable->fdi;
@@ -2092,95 +2193,25 @@ icxLuLut *p /* Object being initialised */
switch(clutos) {
case icxSigJabData:
case icSigLabData: {
- co pp; /* Room for all the solutions found */
- int nsoln; /* Number of solutions found */
- double cdir[MXDO]; /* Clip vector direction and length */
p->clip.LabLike = 1;
- /* Find high clip target */
- for (i = 0; i < p->inputChan; i++)
- pp.p[i] = 0.0; /* Set aux values */
- pp.v[0] = 105.0; pp.v[1] = pp.v[2] = 0.0; /* PCS Target value */
- cdir[0] = cdir[1] = cdir[2] = 0.0; /* Clip Target */
-
- p->inv_output(p, pp.v, pp.v); /* Compensate for output curve */
- p->inv_output(p, cdir, cdir);
-
- cdir[0] -= pp.v[0]; /* Clip vector */
- cdir[1] -= pp.v[1];
- cdir[2] -= pp.v[2];
-
- /* PCS -> Device with clipping */
- nsoln = p->clutTable->rev_interp(
- p->clutTable, /* rspl object */
- 0, /* No hint flags - might be in gamut, might vector clip */
- 1, /* Maxumum solutions to return */
- p->auxm, /* Auxiliary input targets */
- cdir, /* Clip vector direction and length */
- &pp); /* Input target and output solutions */
- /* returned solutions in pp[0..retval-1].p[] */
- nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
-
- if (nsoln != 1) {
- p->pp->errc = 2;
- sprintf(p->pp->err,"Failed to find high clip target for Lab space");
- return p->pp->errc;
- }
-
- p->clip.ocent[0] = pp.v[0] - 0.001; /* Got main target */
- p->clip.ocent[1] = pp.v[1];
- p->clip.ocent[2] = pp.v[2];
-
- /* Find low clip target */
- pp.v[0] = -5.0; pp.v[1] = pp.v[2] = 0.0; /* PCS Target value */
- cdir[0] = 100.0; cdir[1] = cdir[2] = 0.0; /* Clip Target */
-
- p->inv_output(p, pp.v, pp.v); /* Compensate for output curve */
- p->inv_output(p, cdir, cdir);
- cdir[0] -= pp.v[0]; /* Clip vector */
- cdir[1] -= pp.v[1];
- cdir[2] -= pp.v[2];
-
- /* PCS -> Device with clipping */
- nsoln = p->clutTable->rev_interp(
- p->clutTable, /* rspl object */
- RSPL_WILLCLIP, /* Since there was no locus, we expect to have to clip */
- 1, /* Maxumum solutions to return */
- NULL, /* No auxiliary input targets */
- cdir, /* Clip vector direction and length */
- &pp); /* Input target and output solutions */
- /* returned solutions in pp[0..retval-1].p[] */
- nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
- if (nsoln != 1) {
- p->pp->errc = 2;
- sprintf(p->pp->err,"Failed to find low clip target for Lab space");
- return p->pp->errc;
- }
-
- p->clip.ocentv[0] = pp.v[0] + 0.001 - p->clip.ocent[0]; /* Raw line vector */
- p->clip.ocentv[1] = pp.v[1] - p->clip.ocent[1];
- p->clip.ocentv[2] = pp.v[2] - p->clip.ocent[2];
-
- /* Compute vectors length */
- for (p->clip.ocentl = 0.0, i = 0; i < 3; i++)
- p->clip.ocentl += p->clip.ocentv[i] * p->clip.ocentv[i];
- p->clip.ocentl = sqrt(p->clip.ocentl);
- if (p->clip.ocentl <= 1e-8)
- p->clip.ocentl = 0.0;
-
+ /* Create a CuspMap to point vectors towards */
+ /* (Don't make it too fine, or there will be dips) */
+ p->clip.cm = p->get_cuspmap((icxLuBase *)p, 30);
break;
}
case icSigXYZData:
// ~~~~~~1 need to add this.
+ warning("xlut.c: setup_clip_icxLuLut() icSigXYZData case not implemented!");
+ /* Fall through */
default:
/* Do a crude approximation, that may not work. */
p->clutTable->get_out_range(p->clutTable, tmin, tmax);
- for (i = 0; i < p->clutTable->fdi; i++) {
+ for (i = 0; i < p->clutTable->fdi; i++)
p->clip.ocent[i] = (tmin[i] + tmax[i])/2.0;
- }
- p->clip.ocentl = 0.0;
+
break;
}
}
@@ -2306,13 +2337,13 @@ fprintf(stderr,"~1 Internal optimised 4D separations not yet implemented!\n");
/* Init the CAM model if it will be used */
if (pcsor == icxSigJabData || p->camclip) {
- if (vc != NULL) /* One has been provided */
+ if (vc != NULL) /* One has been provided */
p->vc = *vc; /* Copy the structure */
else
xicc_enum_viewcond(xicp, &p->vc, -1, NULL, 0, NULL); /* Use a default */
p->cam = new_icxcam(cam_default);
p->cam->set_view(p->cam, p->vc.Ev, p->vc.Wxyz, p->vc.La, p->vc.Yb, p->vc.Lv,
- p->vc.Yf, p->vc.Yg, p->vc.Gxyz, XICC_USE_HK);
+ p->vc.Yf, p->vc.Yg, p->vc.Gxyz, XICC_USE_HK, p->vc.hkscale);
} else {
p->cam = NULL;
}
@@ -2330,8 +2361,8 @@ fprintf(stderr,"~1 Internal optimised 4D separations not yet implemented!\n");
p->pcs = pcsor;
if (xicp->pp->header->deviceClass == icSigAbstractClass) {
- p->ins = pcsor;
- p->outs = pcsor;
+ p->ins = pcsor;
+ p->outs = pcsor;
} else if (xicp->pp->header->deviceClass != icSigLinkClass) {
if (func == icmBwd || func == icmGamut || func == icmPreview)
@@ -2412,13 +2443,21 @@ fprintf(stderr,"~1 Internal optimised 4D separations not yet implemented!\n");
/* ------------------------------- */
{
int gres[MXDI];
+ int xflags = 0;
for (i = 0; i < p->inputChan; i++)
gres[i] = p->lut->clutPoints;
+#ifdef FASTREVSETUP_NON_CAM
+ /* Don't fill in nnrev array if we aren't going to use it */
+ if (p->camclip && p->nearclip)
+ xflags = RSPL_FASTREVSETUP;
+#endif
+
/* Create rspl based multi-dim table */
if ((p->clutTable = new_rspl((p->fastsetup ? RSPL_FASTREVSETUP : RSPL_NOFLAGS)
- | (flags & ICX_VERBOSE ? RSPL_VERBOSE : RSPL_NOFLAGS),
+ | (flags & ICX_VERBOSE ? RSPL_VERBOSE : RSPL_NOFLAGS)
+ | xflags,
p->inputChan, p->outputChan)) == NULL) {
p->pp->errc = 2;
sprintf(p->pp->err,"Creation of clut table rspl failed");
@@ -2438,6 +2477,17 @@ fprintf(stderr,"~1 Internal optimised 4D separations not yet implemented!\n");
}
+#ifdef USELCHWEIGHT
+ /* If we are not doing camclip, but our output is an Lab like space, */
+ /* then apply lchw weighting anyway. */
+ if (!p->camclip && (p->outs == icSigLabData || p->outs == icxSigJabData)) {
+ double lchw[MXRO] = { JCCWEIGHT, CCCWEIGHT, HCCWEIGHT };
+
+ /* Set the Nearest Neighbor clipping Weighting */
+ p->clutTable->rev_set_lchw(p->clutTable, lchw);
+ }
+#endif /* USELCHWEIGHT */
+
/* clut clipping is setup separately */
}
@@ -2500,22 +2550,24 @@ icxLuLut_clut_camclip_func(
luluto->output(luluto, out, out);
luluto->out_abs(luluto, out, out);
p->cam->XYZ_to_cam(p->cam, out, out);
- out[0] *= CCJSCALE;
}
/* Initialise the additional CAM space clut rspl, used to compute */
/* reverse lookup CAM clipping results when the camclip flag is set. */
-/* We scale J by CCJSCALE, to give a more L* preserving clip direction */
-/* return error code. */
+/* We weight the CAM nn clipping, to give a more L* and H* preserving clip direction. */
+/* Return error code. */
+/* (We are assuming nearest clipping - we aren't setting up properly for */
+/* vector clipping) */
static int
icxLuLut_init_clut_camclip(
icxLuLut *p) {
int e, gres[MXDI];
+ double lchw[MXRO] = { JCCWEIGHT, CCCWEIGHT, HCCWEIGHT };
/* Setup so clut contains transform to CAM Jab */
/* (camclip is only used in fwd or invfwd direction lookup) */
double cmin[3], cmax[3];
- cmin[0] = 0.0; cmax[0] = CCJSCALE * 100.0; /* Nominal Jab output ranges */
+ cmin[0] = 0.0; cmax[0] = 100.0; /* Nominal Jab output ranges */
cmin[1] = -128.0; cmax[1] = 128.0;
cmin[2] = -128.0; cmax[2] = 128.0;
@@ -2536,6 +2588,11 @@ icxLuLut *p) {
return p->pp->errc;
}
+#ifdef USELCHWEIGHT
+ /* Set the Nearest Neighbor clipping Weighting */
+ p->cclutTable->rev_set_lchw(p->cclutTable, lchw);
+#endif /* USELCHWEIGHT */
+
for (e = 0; e < p->inputChan; e++)
gres[e] = p->lut->clutPoints;
@@ -3899,7 +3956,7 @@ int quality /* Quality metric, 0..3 */
xicc_enum_viewcond(xicp, &p->vc, -1, NULL, 0, NULL); /* Use a default */
p->cam = new_icxcam(cam_default);
p->cam->set_view(p->cam, p->vc.Ev, p->vc.Wxyz, p->vc.La, p->vc.Yb, p->vc.Lv,
- p->vc.Yf, p->vc.Yg, p->vc.Gxyz, XICC_USE_HK);
+ p->vc.Yf, p->vc.Yg, p->vc.Gxyz, XICC_USE_HK, p->vc.hkscale);
if (flags & ICX_VERBOSE)
printf("Done A to B table creation\n");
@@ -3912,7 +3969,7 @@ int quality /* Quality metric, 0..3 */
/* ========================================================== */
-/* Context for creating gamut boundary points fro, xicc */
+/* Context for creating gamut boundary points from, xicc */
typedef struct {
gamut *g; /* Gamut being created */
icxLuLut *x; /* xLut we are working from */
@@ -4096,9 +4153,9 @@ double detail /* gamut detail level, 0.0 = def */
}
/* Scan only device surface */
- for (m1 = 0; m1 < inn; m1++) { /* Choose first coord to scan */
+ for (m1 = 0; m1 < (inn-1); m1++) { /* Choose first coord to scan */
if (co[m1] != 0)
- continue; /* Not at lower corner */
+ continue; /* Not at lower corner */
for (m2 = m1 + 1; m2 < inn; m2++) { /* Choose second coord to scan */
int x, y;
@@ -4216,7 +4273,7 @@ double detail /* gamut detail level, 0.0 = def */
default:
break;
}
- if ((cx.flu = p->get_luobj(p, ICX_CLIP_NEAREST , icmFwd, intent, pcs, icmLuOrdNorm,
+ if ((cx.flu = p->get_luobj(p, ICX_CLIP_NEAREST, icmFwd, intent, pcs, icmLuOrdNorm,
&plu->vc, NULL)) == NULL) {
return NULL; /* oops */
}
@@ -4314,6 +4371,304 @@ double detail /* gamut detail level, 0.0 = def */
return gam;
}
+/* ========================================================== */
+/* Cusp Map finding code. */
+/* ========================================================== */
+
+/* Context for creating Cusp Map points from, xicc */
+typedef struct {
+ icxCuspMap *cm; /* Cusp Map being created */
+ icxLuLut *x; /* xLut we are working from */
+ icxLuBase *flu; /* Forward xlookup */
+ double in[MAX_CHAN]; /* Device input values */
+} lutcuspmapctx;
+
+/* Function to pass to rspl to create cusp map from */
+/* forward xLut transform grid points. */
+static void
+lutfwdcuspmap_func(
+ void *pp, /* lutcuspmapctx structure */
+ double *out, /* output' value at clut grid point (ie. PCS' value) */
+ double *in /* input' value at clut grid point (ie. device' value) */
+) {
+ lutcuspmapctx *p = (lutcuspmapctx *)pp;
+ double pcso[3]; /* PCS output value */
+
+ /* Figure if we are over the ink limit. */
+ if ( (p->x->ink.tlimit >= 0.0 || p->x->ink.klimit >= 0.0)
+ && icxLimitD(p->x, in) > 0.0) {
+ int i;
+ double sf;
+
+ /* We are, so use the bracket search to discover a scale */
+ /* for the clut input' value that will put us on the ink limit. */
+
+ for (i = 0; i < p->x->inputChan; i++)
+ p->in[i] = in[i];
+
+ if (zbrent(&sf, 0.0, 1.0, 1e-4, icxLimitFind, pp) != 0) {
+ return; /* Give up */
+ }
+
+ /* Compute ink limit value */
+ for (i = 0; i < p->x->inputChan; i++)
+ p->in[i] = sf * in[i];
+
+ /* Compute the clut output for this clut input */
+ p->x->clut(p->x, pcso, p->in);
+ p->x->output(p->x, pcso, pcso);
+ p->x->out_abs(p->x, pcso, pcso);
+ } else { /* No ink limiting */
+ /* Convert the clut PCS' values to PCS output values */
+ p->x->output(p->x, pcso, out);
+ p->x->out_abs(p->x, pcso, pcso);
+ }
+
+ /* Expand the usp map surface with this point */
+ p->cm->expand(p->cm, pcso);
+
+ /* Leave out[] unchanged */
+}
+
+/* Expand cusp map with given point */
+/* (We use a segmentned maxima approach) */
+static void cuspmap_expand(icxCuspMap *p, double lab[3]) {
+ double h, C;
+ int ix;
+
+ /* Hue angle 0.0 .. 1.0 */
+ h = (0.5/3.14159265359) * atan2(lab[2], lab[1]);
+ h = (h < 0.0) ? h + 1.0 : h;
+
+ /* Slot index 0..res-1 */
+ ix = (int)floor(h * p->res + 0.5);
+ if (ix >= p->res)
+ ix -= p->res;
+
+ /* Chromanance */
+ C = sqrt(lab[1] * lab[1] + lab[2] * lab[2]);
+
+ /* New point at this angle with largest chromanance */
+ if (C > p->C[ix]) {
+ p->C[ix] = C;
+ p->L[ix] = lab[0];
+ }
+
+ /* Tracl min * max L */
+ if (lab[0] > p->Lmax[0])
+ icmCpy3(p->Lmax, lab);
+ if (lab[0] < p->Lmin[0])
+ icmCpy3(p->Lmin, lab);
+}
+
+/* Interpolate over any gaps in map */
+static void cuspmap_complete(icxCuspMap *p) {
+ int i, j, k;
+
+// printf("cuspmap list before fixups:\n");
+// for (i = 0; i < p->res; i++) {
+// printf(" %d: C = %f, L = %f\n",i, p->C[i], p->L[i]);
+// }
+
+ /* First check if there are any entries at all */
+ for (i = 0; i < p->res; i++) {
+ if (p->C[i] >= 0.0)
+ break;
+ }
+
+ if (i >= p->res) /* Nothing there - give up */
+ return;
+
+ /* See if there are any gaps */
+ j = -1;
+ for (i = 0; i < p->res; i++) {
+//printf("~1 checking %d\n",i);
+ if (p->C[i] >= 0.0) {
+ j = i; /* Last valid slot */
+//printf("~1 last valid %d\n",j);
+
+ /* Got a gap */
+ } else {
+ int ii = i;
+//printf("~1 found gap at %d\n",i);
+ if (j < 0) { /* No previous */
+//printf("~1 no previous\n");
+ for (j = p->res-1; j >= 0; j--) {
+ if (p->C[j] >= 0.0)
+ break;
+ }
+ }
+//printf("~1 got previous %d\n",j);
+ /* Find next, even if it's behind us */
+ for (k = i+1; k != i; k = (k+1) % p->res) {
+ if (p->C[k] >= 0.0)
+ break;
+ }
+//printf("~1 got next %d\n",k);
+
+ /* Interpolate between them */
+ for (; i != k; i = (i+1) % p->res) {
+ double prop;
+ int bb, tt;
+ bb = k > i ? k - i : k + p->res - i;
+ tt = k > j ? k - j : k + p->res - j;
+ prop = (double)bb/(double)tt;
+ p->C[i] = prop * p->C[j] + (1.0 - prop) * p->C[k];
+ p->L[i] = prop * p->L[j] + (1.0 - prop) * p->L[k];
+//printf("~1 interpolating %d with weight %f from %d and %d\n",i,prop,j,k);
+ }
+ if (k > ii) {
+ i = k; /* Continue from next valid */
+//printf("~1 continuing from %d\n",i);
+ } else {
+//printf("~1 we've looped back\n");
+ break; /* We've looped back */
+ }
+ }
+ }
+
+// printf("cuspmap list after fixups:\n");
+// for (i = 0; i < p->res; i++) {
+// printf(" %d: C = %f, L = %f\n",i, p->C[i], p->L[i]);
+// }
+}
+
+/* Return the corresponding cusp location, given the source point */
+static void cuspmap_getCusp(icxCuspMap *p,double cuspLCh[3], double srcLab[3]) {
+ double h, C;
+ int ix, ix0, ix1;
+
+ /* Hue angle 0.0 .. 1.0 */
+ h = (0.5/3.14159265359) * atan2(srcLab[2], srcLab[1]);
+ h = (h < 0.0) ? h + 1.0 : h;
+
+//printf("~1 getCusp in %f %f %f, h = %f\n", srcLab[0], srcLab[1], srcLab[2],h);
+
+ /* Slot index 0..res-1 */
+ ix = (int)floor(h * p->res + 0.5);
+ if (ix >= p->res)
+ ix -= p->res;
+
+ /* Indexes each side */
+ ix0 = ix > 0 ? ix-1 : p->res-1;
+ ix1 = ix < (p->res-1) ? ix+1 : 0;
+
+ cuspLCh[0] = p->L[ix];
+ cuspLCh[1] = p->C[ix];
+ if (cuspLCh[1] > p->C[ix0]) /* Be conservative with C value */
+ cuspLCh[1] = p->C[ix0];
+ if (cuspLCh[1] > p->C[ix1])
+ cuspLCh[1] = p->C[ix1];
+ cuspLCh[2] = 360.0 * h;
+
+//printf("~1 index %d, L %f C %f h %f\n", ix, cuspLCh[0], cuspLCh[1], cuspLCh[2]);
+}
+
+/* We're done with CuspMap */
+static void cuspmap_del(icxCuspMap *p) {
+ if (p != NULL) {
+ if (p->L != NULL)
+ free(p->L);
+ if (p->C != NULL)
+ free(p->C);
+ free(p);
+ }
+}
+
+/* Given an xicc lookup object, return an icxCuspMap object. */
+/* Note that the PCS must be Lab or Jab. */
+/* An icxLuLut type must be icmFwd, and the ink limit (if supplied) */
+/* will be applied. */
+/* Return NULL on error, check errc+err for reason */
+static icxCuspMap *icxLuLutCuspMap(
+icxLuBase *plu, /* this */
+int res /* Hue resolution */
+) {
+ xicc *p = plu->pp; /* parent xicc */
+ icxLuLut *luluto = (icxLuLut *)plu; /* Lookup xLut type object */
+ icColorSpaceSignature ins, pcs, outs;
+ icmLookupFunc func;
+ icRenderingIntent intent;
+ int inn, outn;
+ lutcuspmapctx cx;
+ icxCuspMap *cm;
+ int i;
+
+ /* get some details */
+ plu->spaces(plu, &ins, &inn, &outs, &outn, NULL, &intent, &func, &pcs);
+
+ if (func != icmFwd) {
+ p->errc = 1;
+ sprintf(p->err,"Creating CuspMap for anything other than Device -> PCS is not supported.");
+ return NULL;
+ }
+
+ if (pcs != icSigLabData && pcs != icxSigJabData) {
+ p->errc = 1;
+ sprintf(p->err,"Creating CuspMap PCS of other than Lab or Jab is not supported.");
+ return NULL;
+ }
+
+ cx.cm = cm = (icxCuspMap *) calloc(1, sizeof(icxCuspMap));
+ cx.x = luluto;
+
+ if (cx.cm == NULL) {
+ p->errc = 2;
+ sprintf(p->err,"Malloc of icxCuspMap failed");
+ return NULL;
+ }
+
+ if ((cm->L = (double *)malloc(sizeof(double) * res)) == NULL) {
+ free(cm);
+ p->errc = 2;
+ sprintf(p->err,"Malloc of icxCuspMap failed");
+ return NULL;
+ }
+
+ if ((cm->C = (double *)malloc(sizeof(double) * res)) == NULL) {
+ free(cm->L);
+ free(cm);
+ p->errc = 2;
+ sprintf(p->err,"Malloc of icxCuspMap failed");
+ return NULL;
+ }
+
+ cm->res = res;
+ cm->expand = cuspmap_expand;
+ cm->getCusp = cuspmap_getCusp;
+ cm->del = cuspmap_del;
+
+ for (i = 0; i < res; i++) {
+ cm->L[i] = -1.0;
+ cm->C[i] = -1.0;
+ }
+ cm->Lmax[0] = -1.0;
+ cm->Lmin[0] = 101.0;
+
+ /* Scan through grid, expanding the CuspMap. */
+ luluto->clutTable->scan_rspl(
+ luluto->clutTable, /* this */
+ RSPL_NOFLAGS, /* Combination of flags */
+ (void *)&cx, /* Opaque function context */
+ lutfwdcuspmap_func /* Function to set from */
+ );
+
+ cm->Lmax[0] -= 0.1; /* Make sure tips intersect */
+ cm->Lmin[0] += 0.1;
+
+ for (i = 0; i < res; i++) {
+ if (cm->L[i] > cm->Lmax[0])
+ cm->L[i] = cm->Lmax[0];
+ if (cm->L[i] < cm->Lmin[0])
+ cm->L[i] = cm->Lmin[0];
+ }
+
+ /* Fill in any gaps */
+ cuspmap_complete(cm);
+
+ return cm;
+}
+
/* ----------------------------------------------- */
#ifdef DEBUG
#undef DEBUG /* Limit extent to this file */
diff --git a/xicc/xmatrix.c b/xicc/xmatrix.c
index 3d4fca6..c18ef1c 100644
--- a/xicc/xmatrix.c
+++ b/xicc/xmatrix.c
@@ -223,6 +223,7 @@ double *out, double *in) {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static gamut *icxLuMatrixGamut(icxLuBase *plu, double detail);
+static icxCuspMap *icxLuMatrixCuspMap(icxLuBase *plu, int res) { return NULL; };
/* Do the basic icxLuMatrix creation and initialisation */
static icxLuMatrix *
@@ -246,6 +247,7 @@ alloc_icxLuMatrix(
p->get_ranges = icxLu_get_ranges;
p->efv_wh_bk_points = icxLuEfv_wh_bk_points;
p->get_gamut = icxLuMatrixGamut;
+ p->get_cuspmap = icxLuMatrixCuspMap;
p->fwd_relpcs_outpcs = icxLuMatrix_fwd_relpcs_outpcs;
p->bwd_outpcs_relpcs = icxLuMatrix_bwd_outpcs_relpcs;
@@ -315,7 +317,7 @@ int dir /* 0 = fwd, 1 = bwd */
xicc_enum_viewcond(xicp, &p->vc, -1, NULL, 0, NULL); /* Use a default */
p->cam = new_icxcam(cam_default);
p->cam->set_view(p->cam, p->vc.Ev, p->vc.Wxyz, p->vc.La, p->vc.Yb, p->vc.Lv,
- p->vc.Yf, p->vc.Yg, p->vc.Gxyz, XICC_USE_HK);
+ p->vc.Yf, p->vc.Yg, p->vc.Gxyz, XICC_USE_HK, p->vc.hkscale);
} else {
p->cam = NULL;
}
@@ -1136,7 +1138,7 @@ static void icxMM_force_exact(icxMatrixModel *p, double *targ, double *rgb) {
icmAry2XYZ(_ap, axyz);
icmAry2XYZ(_tp, txyz);
if (p->picc != NULL)
- p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, _tp, _ap, cmat);
+ p->picc->chromAdaptMatrix(p->picc, ICM_CAM_NONE, NULL, cmat, _tp, _ap);
else
icmChromAdaptMatrix(ICM_CAM_BRADFORD, _tp, _ap, cmat);
@@ -1508,11 +1510,9 @@ double smooth /* Curve smoothing, nominally 1.0 */
icmXYZNumber _wp;
icmAry2XYZ(_wp, wp);
- /* Absolute->Aprox. Relative Adaptation matrix */
- icco->chromAdaptMatrix(icco, ICM_CAM_NONE, icmD50, _wp, fromAbs);
-
+ /* Absolute->Aprox. Relative Adaptation matrix, and */
/* Aproximate relative to absolute conversion matrix */
- icco->chromAdaptMatrix(icco, ICM_CAM_NONE, _wp, icmD50, toAbs);
+ icco->chromAdaptMatrix(icco, ICM_CAM_NONE, toAbs, fromAbs, icmD50, _wp);
}
} else {
@@ -1618,7 +1618,7 @@ printf(" set black %d w = %f\n", nodp,rpoints[nodp].w);
/* Matrix needed to correct aprox white to target D50 */
icmAry2XYZ(_wp, aw); /* Aprox relative target white point */
- icco->chromAdaptMatrix(icco, ICM_CAM_NONE, icmD50, _wp, cmat); /* Correction */
+ icco->chromAdaptMatrix(icco, ICM_CAM_NONE, NULL, cmat, icmD50, _wp); /* Correction */
/* Compute the current absolute white point */
icmMulBy3x3(wp, toAbs, aw);
@@ -1628,8 +1628,7 @@ printf(" set black %d w = %f\n", nodp,rpoints[nodp].w);
/* Fix relative conversions to leave absolute response unchanged. */
icmAry2XYZ(_wp, wp); /* Actual white point */
- icco->chromAdaptMatrix(icco, ICM_CAM_NONE, icmD50, _wp, fromAbs);
- icco->chromAdaptMatrix(icco, ICM_CAM_NONE, _wp, icmD50, toAbs);
+ icco->chromAdaptMatrix(icco, ICM_CAM_NONE, toAbs, fromAbs, icmD50, _wp);
if (flags & ICX_VERBOSE) {
double tw[3];
@@ -1723,8 +1722,7 @@ printf(" set black %d w = %f\n", nodp,rpoints[nodp].w);
/* Fix absolute conversions to leave absolute response unchanged. */
icmAry2XYZ(_wp, wp); /* Actual white point */
- icco->chromAdaptMatrix(icco, ICM_CAM_NONE, icmD50, _wp, fromAbs);
- icco->chromAdaptMatrix(icco, ICM_CAM_NONE, _wp, icmD50, toAbs);
+ icco->chromAdaptMatrix(icco, ICM_CAM_NONE, toAbs, fromAbs, icmD50, _wp);
}
/* Look up the actual black point */
diff --git a/xicc/xmono.c b/xicc/xmono.c
index fe9c55e..d1f091b 100644
--- a/xicc/xmono.c
+++ b/xicc/xmono.c
@@ -194,6 +194,7 @@ double *out, double *in) {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static gamut *icxLuMonoGamut(icxLuBase *plu, double detail);
+static icxCuspMap *icxLuMonoCuspMap(icxLuBase *plu, int res) { return NULL; };
static icxLuBase *
new_icxLuMono(
@@ -222,6 +223,7 @@ int dir /* 0 = fwd, 1 = bwd */
p->get_ranges = icxLu_get_ranges;
p->efv_wh_bk_points = icxLuEfv_wh_bk_points;
p->get_gamut = icxLuMonoGamut;
+ p->get_cuspmap = icxLuMonoCuspMap;
p->fwd_relpcs_outpcs = icxLuMono_fwd_relpcs_outpcs;
p->bwd_outpcs_relpcs = icxLuMono_bwd_outpcs_relpcs;
p->nearclip = 0; /* Set flag defaults */
@@ -262,7 +264,7 @@ int dir /* 0 = fwd, 1 = bwd */
p->vc = *vc; /* Copy the structure */
p->cam = new_icxcam(cam_default);
p->cam->set_view(p->cam, vc->Ev, vc->Wxyz, vc->La, vc->Yb, vc->Lv, vc->Yf, vc->Yg, vc->Gxyz,
- XICC_USE_HK);
+ XICC_USE_HK, vc->hkscale);
} else
p->cam = NULL;
diff --git a/xicc/xspect.c b/xicc/xspect.c
index 6738113..9df298e 100644
--- a/xicc/xspect.c
+++ b/xicc/xspect.c
@@ -42,6 +42,7 @@
# include "plot.h" /* For debugging */
#else
# include "numsup.h"
+# include "sa_conv.h"
#endif
#include "conv.h"
#include "xspect.h"
@@ -291,7 +292,6 @@ static xspect il_D65 = {
}
};
-#ifndef SALONEINSTLIB
/* General temperature Daylight spectra (Using OLDER CIE 1960 u,v CCT) */
/* 300 - 830nm ub 5nm intervals. */
/* Fill in the given xspect with the specified daylight illuminant */
@@ -511,8 +511,6 @@ static int daylight_il(xspect *sp, double ct) {
return 0;
}
-#endif /* !SALONEINSTLIB */
-
/* General temperature Planckian (black body) spectra using CIE 15:2004 */
/* Fill in the given xspect with the specified Planckian illuminant */
/* normalised so that 560nm = 100. */
@@ -744,11 +742,11 @@ double temp /* Optional temperature in degrees kelvin, for Dtemp and Ptemp *
case icxIT_Spectrocam:
*sp = il_Spectrocam;
return 0;
+#endif
case icxIT_ODtemp:
return daylight_old_il(sp, temp);
case icxIT_Dtemp:
return daylight_il(sp, temp);
-#endif
case icxIT_OPtemp:
return planckian_old_il(sp, temp);
case icxIT_Ptemp:
@@ -3819,10 +3817,37 @@ static xspect FWA1_emit = {
#endif /* STOCKFWA */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Return a string describing the inst_meas_type */
+char *meas_type2str(inst_meas_type mt) {
+
+ switch (mt) {
+ case inst_mrt_none:
+ return "None";
+ case inst_mrt_emission:
+ return "Emission";
+ case inst_mrt_ambient:
+ return "Ambient";
+ case inst_mrt_emission_flash:
+ return "Emission Flash";
+ case inst_mrt_ambient_flash:
+ return "Ambient Flash";
+ case inst_mrt_reflective:
+ return "Reflective";
+ case inst_mrt_transmissive:
+ return "Transmissive";
+ case inst_mrt_sensitivity:
+ return "Sensitivity";
+ case inst_mrt_frequency:
+ return "Frequency";
+ }
+ return "Unknown";
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* save a set of spectrum to a CGATS file */
/* type 0 = SPECT, 1 = CMF */
/* Return NZ on error */
-int write_nxspect(char *fname, xspect *sp, int nspec, int type) {
+int write_nxspect(char *fname, inst_meas_type mt, xspect *sp, int nspec, int type) {
char buf[100];
time_t clk = time(0);
struct tm *tsp = localtime(&clk);
@@ -3844,6 +3869,33 @@ int write_nxspect(char *fname, xspect *sp, int nspec, int type) {
atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+ if (mt != inst_mrt_none) {
+ char *tag = NULL;
+ switch (mt) {
+ case inst_mrt_emission:
+ tag = "EMISSION"; break;
+ case inst_mrt_ambient:
+ tag = "AMBIENT"; break;
+ case inst_mrt_emission_flash:
+ tag = "EMISSION_FLASH"; break;
+ case inst_mrt_ambient_flash:
+ tag = "AMBIENT_FLASH"; break;
+ case inst_mrt_reflective:
+ tag = "REFLECTIVE"; break;
+ case inst_mrt_transmissive:
+ tag = "TRANSMISSIVE"; break;
+ case inst_mrt_sensitivity:
+ tag = "SENSITIVITY"; break;
+ default:
+ break;
+ }
+ if (tag != NULL)
+ ocg->add_kword(ocg, 0, "MEAS_TYPE",tag, NULL);
+ }
+
+ sprintf(buf,"%d", sp->spec_n);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+
sprintf(buf,"%d", sp->spec_n);
ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
sprintf(buf,"%f", sp->spec_wl_short);
@@ -3889,13 +3941,14 @@ int write_nxspect(char *fname, xspect *sp, int nspec, int type) {
}
/* Restore a set of spectrum from a CGATS file. */
-/* Up to nspec will be restored starting at offset off.. */
+/* Up to nspec will be restored starting at offset off. */
/* The number restored from the file will be written to *nret */
-/* type: 0 = any, mask: 1 = SPECT, 2 = CMF, 4 = ccss */
+/* File type: 0 = any, mask: 1 = SPECT, 2 = CMF, 4 = ccss */
/* (Note that not all ccss information is read. Use ccss->read_ccss() for this. */
/* Return NZ on error */
/* (Would be nice to return an error message!) */
-int read_nxspect(xspect *sp, char *fname, int *nret, int off, int nspec, int type) {
+int read_nxspect(xspect *sp, inst_meas_type *mt, char *fname,
+ int *nret, int off, int nspec, int type) {
cgats *icg; /* input cgats structure */
char buf[100];
int sflds[XSPECT_MAX_BANDS];
@@ -3931,6 +3984,26 @@ int read_nxspect(xspect *sp, char *fname, int *nret, int off, int nspec, int typ
return 1;
}
+ if (mt != NULL && (ii = icg->find_kword(icg, 0, "MEAS_TYPE")) >= 0) {
+
+ if (strcmp(icg->t[0].kdata[ii], "EMISSION") == 0)
+ *mt = inst_mrt_emission;
+ else if (strcmp(icg->t[0].kdata[ii], "AMBIENT") == 0)
+ *mt = inst_mrt_ambient;
+ else if (strcmp(icg->t[0].kdata[ii], "EMISSION_FLASH") == 0)
+ *mt = inst_mrt_emission_flash;
+ else if (strcmp(icg->t[0].kdata[ii], "AMBIENT_FLASH") == 0)
+ *mt = inst_mrt_ambient_flash;
+ else if (strcmp(icg->t[0].kdata[ii], "REFLECTIVE") == 0)
+ *mt = inst_mrt_reflective;
+ else if (strcmp(icg->t[0].kdata[ii], "TRANSMISSIVE") == 0)
+ *mt = inst_mrt_transmissive;
+ else if (strcmp(icg->t[0].kdata[ii], "SENSITIVITY") == 0)
+ *mt = inst_mrt_sensitivity;
+ else
+ *mt = inst_mrt_none;
+ }
+
if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0) {
DBG ("Input file doesn't contain keyword SPECTRAL_BANDS\n");
icg->del(icg);
@@ -3980,12 +4053,12 @@ int read_nxspect(xspect *sp, char *fname, int *nret, int off, int nspec, int typ
}
/* Read all the spectra */
- for (j = off; j < nspec && j < icg->t[0].nsets; j++) {
+ for (j = off; j < (off + nspec) && j < icg->t[0].nsets; j++) {
- XSPECT_COPY_INFO(&sp[j], &proto);
+ XSPECT_COPY_INFO(&sp[j-off], &proto);
for (i = 0; i < proto.spec_n; i++) {
- sp[j].spec[i] = *((double *)icg->t[0].fdata[j][sflds[i]]);
+ sp[j-off].spec[i] = *((double *)icg->t[0].fdata[j][sflds[i]]);
}
}
if (nret != NULL)
@@ -4000,17 +4073,17 @@ int read_nxspect(xspect *sp, char *fname, int *nret, int off, int nspec, int typ
/* save a spectrum to a CGATS file */
/* Return NZ on error */
-int write_xspect(char *fname, xspect *sp) {
- return write_nxspect(fname, sp, 1, 0);
+int write_xspect(char *fname, inst_meas_type mt, xspect *sp) {
+ return write_nxspect(fname, mt, sp, 1, 0);
}
/* restore a spectrum from a CGATS file */
/* Return NZ on error */
/* (Would be nice to return an error message!) */
-int read_xspect(xspect *sp, char *fname) {
+int read_xspect(xspect *sp, inst_meas_type *mt, char *fname) {
int rv, nret;
- if ((rv = read_nxspect(sp, fname, &nret, 0, 1, 1)) != 0)
+ if ((rv = read_nxspect(sp, mt, fname, &nret, 0, 1, 1)) != 0)
return rv;
if (nret != 1) {
DBG("Didn't read one spectra\n");
@@ -4024,19 +4097,25 @@ int read_xspect(xspect *sp, char *fname) {
/* save a set of 3 spectrum to a CGATS CMF file */
/* Return NZ on error */
int write_cmf(char *fname, xspect sp[3]) {
- return write_nxspect(fname, sp, 3, 1);
+ return write_nxspect(fname, inst_mrt_sensitivity, sp, 3, 1);
}
/* restore a spectrum from a CGATS file */
/* Return NZ on error */
/* (Would be nice to return an error message!) */
int read_cmf(xspect sp[3], char *fname) {
+ inst_meas_type mt;
int rv, nret;
- if ((rv = read_nxspect(sp, fname, &nret, 0, 3, 2)) != 0) {
+ /* Hmm. Should we check inst_meas_type is none || sensitivity ? */
+ if ((rv = read_nxspect(sp, &mt, fname, &nret, 0, 3, 2)) != 0) {
DBG("read_nxspect failed\n");
return rv;
}
+ if (mt != inst_mrt_none && mt != inst_mrt_sensitivity) {
+ DBG("read_nxspect - wrong measurement type\n");
+ return 1;
+ }
if (nret != 3) {
DBG("Didn't read three spectra\n");
return 1;
@@ -4050,7 +4129,7 @@ int read_cmf(xspect sp[3], char *fname) {
/* Get a raw 3rd order polinomial interpolated spectrum value. */
-/* Return NZ if value is valid, Z and last valid value */
+/* Return NZ if value is valid, Z and xtrapolated value */
/* if outside the range */
/* NOTE: Returned value isn't normalised by sp->norm */
static int getval_raw_xspec_poly3(xspect *sp, double *rv, double xw) {
@@ -4072,32 +4151,28 @@ static int getval_raw_xspec_poly3(xspect *sp, double *rv, double xw) {
rc = 0;
}
- /* Compute fraction 0.0 - 1.0 out of known spectrum */
+ /* Compute fraction 0.0 - 1.0 out of known spectrum. */
+ /* Place it so that the target wavelength lands in middle section */
+ /* of Lagrange basis points. */
spcing = (sp->spec_wl_long - sp->spec_wl_short)/(sp->spec_n-1.0);
f = (xw - sp->spec_wl_short) / (sp->spec_wl_long - sp->spec_wl_short);
f *= (sp->spec_n - 1.0);
i = (int)floor(f); /* Base grid coordinate */
- if (i < 0) /* Limit to valid cube base index range */
- i = 0;
- else if (i > (sp->spec_n - 2))
- i = (sp->spec_n - 2);
+ if (i < 1) /* Limit to valid Lagrange basis index range, */
+ i = 1; /* and extrapolate from that at ends. */
+ else if (i > (sp->spec_n - 3))
+ i = (sp->spec_n - 3);
/* Setup the surrounding values */
x[0] = sp->spec_wl_short + (i-1) * spcing;
- if (i == 0)
- y[0] = sp->spec[i];
- else
- y[0] = sp->spec[i-1];
+ y[0] = sp->spec[i-1];
x[1] = sp->spec_wl_short + i * spcing;
y[1] = sp->spec[i];
x[2] = sp->spec_wl_short + (i+1) * spcing;
y[2] = sp->spec[i+1];
x[3] = sp->spec_wl_short + (i+2) * spcing;
- if ((i+2) < sp->spec_n)
- y[3] = sp->spec[i+2];
- else
- y[3] = sp->spec[i+1];
+ y[3] = sp->spec[i+2];
#ifndef NEVER
/* Compute interpolated value using Lagrange: */
@@ -4346,13 +4421,14 @@ void xspect2xspect(xspect *dst, xspect *targ, xspect *src) {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Plot up to 3 spectra */
-void xspect_plot(xspect *sp1, xspect *sp2, xspect *sp3) {
- double xx[XSPECT_MAX_BANDS];
- double y1[XSPECT_MAX_BANDS];
- double y2[XSPECT_MAX_BANDS];
- double y3[XSPECT_MAX_BANDS];
+void xspect_plot_w(xspect *sp1, xspect *sp2, xspect *sp3, int wait) {
+ static double xx[XSPECT_MAX_BANDS];
+ static double y1[XSPECT_MAX_BANDS];
+ static double y2[XSPECT_MAX_BANDS];
+ static double y3[XSPECT_MAX_BANDS];
int j;
double wl, wlshort, wllong;
+ double ymax = 0.0;
if (sp1 == NULL)
return;
@@ -4384,14 +4460,28 @@ void xspect_plot(xspect *sp1, xspect *sp2, xspect *sp3) {
#endif
xx[j] = wl;
y1[j] = value_xspect(sp1, wl);
- if (sp2 != NULL)
+ if (y1[j] > ymax)
+ ymax = y1[j];
+ if (sp2 != NULL) {
y2[j] = value_xspect(sp2, wl);
- if (sp3 != NULL)
+ if (y2[j] > ymax)
+ ymax = y2[j];
+ }
+ if (sp3 != NULL) {
y3[j] = value_xspect(sp3, wl);
+ if (y3[j] > ymax)
+ ymax = y3[j];
+ }
}
- do_plot(xx, y1, sp2 != NULL ? y2 : NULL, sp3 != NULL ? y3 : NULL, j);
+// do_plot(xx, y1, sp2 != NULL ? y2 : NULL, sp3 != NULL ? y3 : NULL, j);
+ do_plot_x(xx, y1, sp2 != NULL ? y2 : NULL, sp3 != NULL ? y3 : NULL, j,
+ wait, 0.0, -1.0, 0.0, ymax, 1.0);
}
+/* Plot up to 3 spectra & wait for key */
+void xspect_plot(xspect *sp1, xspect *sp2, xspect *sp3) {
+ xspect_plot_w(sp1, sp2, sp3, 1);
+}
/* Plot up to 10 spectra */
void xspect_plot10(xspect *sp, int n) {
@@ -5644,12 +5734,10 @@ xspect *in /* Spectrum to be converted */
#endif /* CLAMP_XYZ */
}
-#ifndef SALONEINSTLIB
/* If Lab is target, convert to D50 Lab */
if (p->doLab) {
icmXYZ2Lab(&icmD50, out, out);
}
-#endif /* !SALONEINSTLIB */
if (sout != NULL) {
*sout = *in; /* Structure copy */
@@ -5682,9 +5770,9 @@ xsp2cie *p
/* Create and return a new spectral conversion object */
xsp2cie *new_xsp2cie(
icxIllumeType ilType, /* Illuminant */
-xspect *custIllum, /* Optional custom illuminant */
+xspect *custIllum, /* Custom illuminant if ilType == icxIT_custom */
icxObserverType obType, /* Observer */
-xspect custObserver[3], /* Optional custom observer */
+xspect custObserver[3], /* Custom observer if obType == icxOT_custom */
icColorSpaceSignature rcs, /* Return color space, icSigXYZData or D50 icSigLabData */
/* ** Must be icSigXYZData if SALONEINSTLIB ** */
icxClamping clamp /* NZ to clamp XYZ/Lab to be +ve */
@@ -7781,6 +7869,7 @@ int viscct /* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
/* An observer type can be chosen for interpretting the spectrum of the input and */
/* the illuminant. */
/* Return -1.0 on erorr */
+/* (Faster, slightly less accurate version of icx_XYZ2ill_ct()) */
double icx_XYZ2ill_ct2(
double txyz[3], /* If not NULL, return the XYZ of the locus temperature */
icxIllumeType ilType, /* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
@@ -7828,6 +7917,7 @@ int viscct /* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
/* An observer type can be chosen for interpretting the spectrum of the input and */
/* the illuminant. */
/* Return xyz[0] = -1.0 on erorr */
+/* (Faster, slightly less accrurate alternative to standardIlluminant()) */
void icx_ill_ct2XYZ(
double xyz[3], /* Return the XYZ value */
icxIllumeType ilType, /* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
@@ -8780,9 +8870,44 @@ double ct /* Input temperature in degrees K */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given a reflectance/transmittance spectrum, */
+/* an illuminant definition and an observer model, return */
+/* the XYZ value for that spectrum. */
+/* Return 0 on sucess, 1 on error */
+/* (One shot version of xsp2cie etc.) */
+int icx_sp2XYZ(
+double xyz[3], /* Return XYZ value */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+icxIllumeType ilType, /* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
+double ct, /* Input temperature in degrees K */
+xspect *custIllum, /* Optional custom illuminant */
+xspect *sp /* Spectrum to be converted */
+) {
+ xspect ill; /* Xspect to fill in */
+ xsp2cie *conv; /* Means of converting spectrum to XYZ */
+
+ if (ilType == icxIT_custom)
+ ill = *custIllum;
+ else if (standardIlluminant(&ill, ilType, ct) != 0)
+ return 1;
+
+ if ((conv = new_xsp2cie(icxIT_custom, &ill, obType, custObserver, icSigXYZData, 1)) == NULL)
+ return 1;
+
+ conv->convert(conv, xyz, sp);
+
+ conv->del(conv);
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
/* Given an illuminant definition and an observer model, return */
/* the normalised XYZ value for that spectrum. */
/* Return 0 on sucess, 1 on error */
+/* (One shot version of xsp2cie etc.) */
int icx_ill_sp2XYZ(
double xyz[3], /* Return XYZ value with Y == 1 */
icxObserverType obType, /* Observer */
@@ -8816,9 +8941,9 @@ xspect *custIllum /* Optional custom illuminant */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Aproximate CCT using polinomial. No good < 3000K */
-/* Use this for sanity check */
#ifdef NEVER
-static double aprox_CCT(double xyz[3]) {
+/* Hernndez-Andrs, Lee & Romero exponential approximation (more fragile) */
+static double aprox_CCT_Yxy(double Yxy[3]) {
double xe = 0.3366;
double ye = 0.1735;
double A0 = -949.86315;
@@ -8828,29 +8953,62 @@ static double aprox_CCT(double xyz[3]) {
double t2 = 0.20039;
double A3 = 0.00004;
double t3 = 0.07125;
- double Yxy[3];
double n;
double cct;
- icmXYZ2Yxy(Yxy, xyz);
n = (Yxy[1] - xe)/(Yxy[2] - ye);
cct = A0 + A1 * exp(-n/t1) + A2 * exp(-n/t2) + A3 * exp(-n/t3);
return cct;
}
#else
-static double aprox_CCT(double xyz[3]) {
- double Yxy[3];
+/* McCamy's cubic approximation: (more robust) */
+static double aprox_CCT_Yxy(double Yxy[3]) {
double n;
double cct;
- icmXYZ2Yxy(Yxy, xyz);
n = (Yxy[1] - 0.3320)/(Yxy[2] - 0.1858);
cct = -449.0 * n * n * n + 3525.0 * n * n - 6823.3 * n + 5520.33;
return cct;
}
#endif
+double aprox_CCT(double xyz[3]) {
+ double Yxy[3];
+
+ icmXYZ2Yxy(Yxy, xyz);
+
+ return aprox_CCT_Yxy(Yxy);
+}
+
+/* Aproximate x,y from CCT using Kim et al's cubic spline. */
+/* Invalid < 1667 and > 25000 */
+/* (Doesn't set Yxy[0]) */
+void aprox_plankian(double Yxy[3], double ct) {
+ double t1 = 1e3/ct;
+ double t2 = t1 * t1;
+ double t3 = t2 * t1;
+ double xc, xc2, xc3, yc;
+
+ if (ct <= 4000.0)
+ xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t1 + 0.179910;
+ else
+ xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t2 + 0.240390;
+
+ xc2 = xc * xc;
+ xc3 = xc2 * xc;
+
+ if (ct <= 2222.0)
+ yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683;
+ else if (ct <= 4000.0)
+ yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867;
+ else
+ yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483;
+
+ Yxy[1] = xc;
+ Yxy[2] = yc;
+}
+
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Full precision CCT */
diff --git a/xicc/xspect.h b/xicc/xspect.h
index 3e0caeb..3dd99a5 100644
--- a/xicc/xspect.h
+++ b/xicc/xspect.h
@@ -27,7 +27,7 @@
#ifndef SALONEINSTLIB
#include "icc.h" /* icclib ICC definitions */
#else /* SALONEINSTLIB */
-#include "conv.h" /* fake icclib ICC definitions */
+#include "sa_conv.h" /* fake icclib ICC definitions */
#endif /* SALONEINSTLIB */
#ifdef __cplusplus
@@ -36,6 +36,24 @@
/* ------------------------------------------------------------------------------ */
+/* Type of measurement result */
+typedef enum { /* XYZ units, Spectral units */
+ inst_mrt_none = 0, /* Not set */
+ inst_mrt_emission = 1, /* cd/m^2, mW/(m^2.sr.nm) */
+ inst_mrt_ambient = 2, /* Lux mW/(m^2.nm) */
+ inst_mrt_emission_flash = 3, /* cd.s/m^2, mW.s/(m^2.sr.nm) */
+ inst_mrt_ambient_flash = 4, /* Lux.s mW.s/(m^2.nm) */
+ inst_mrt_reflective = 5, /* %, %/nm */
+ inst_mrt_transmissive = 6, /* %, %/nm */
+ inst_mrt_sensitivity = 7, /* %, %/nm */
+ inst_mrt_frequency = 8 /* Hz */
+} inst_meas_type;
+
+/* Return a string describing the inst_meas_type */
+char *meas_type2str(inst_meas_type mt);
+
+/* ------------------------------------------------------------------------------ */
+
/* Structure for conveying spectral information */
/* NOTE :- should ditch norm, and replace it by */
@@ -87,8 +105,8 @@ typedef struct {
#ifndef SALONEINSTLIB
/* Single spectrum utility functions. Return NZ if error */
-int write_xspect(char *fname, xspect *s);
-int read_xspect(xspect *sp, char *fname);
+int write_xspect(char *fname, inst_meas_type mt, xspect *s);
+int read_xspect(xspect *sp, inst_meas_type *mt, char *fname);
/* CMF utility functions. Return NZ if error */
int write_cmf(char *fname, xspect cmf[3]);
@@ -96,11 +114,12 @@ int read_cmf(xspect cmf[3], char *fname);
/* Save a set of nspec spectrum to a CGATS file. Return NZ if error */
/* type 0 = SPECT, 1 = CMF */
-int write_nxspect(char *fname, xspect *sp, int nspec, int type);
+int write_nxspect(char *fname, inst_meas_type mt, xspect *sp, int nspec, int type);
/* Restore a set of up to nspec spectrum from a CGATS file. Return NZ if error */
/* type = any, 1 = SPECT, 2 = CMF, 3 = both */
-int read_nxspect(xspect *sp, char *fname, int *nret, int off, int nspec, int type);
+int read_nxspect(xspect *sp, inst_meas_type *mt,
+ char *fname, int *nret, int off, int nspec, int type);
#endif /* !SALONEINSTLIB*/
@@ -115,6 +134,9 @@ void xspect_denorm(xspect *sp);
void xspect2xspect(xspect *dst, xspect *targ, xspect *src);
/* Plot up to 3 spectra */
+void xspect_plot_w(xspect *sp1, xspect *sp2, xspect *sp3, int wait);
+
+/* Plot up to 3 spectra & wait for key */
void xspect_plot(xspect *sp1, xspect *sp2, xspect *sp3);
/* Plot up to 10 spectra */
@@ -145,9 +167,9 @@ typedef enum {
icxIT_F8 = 12, /* Fluorescent, Broad Band 5000K, CRI 95 */
icxIT_F10 = 13, /* Fluorescent Narrow Band 5000K, CRI 81 */
icxIT_Spectrocam = 14, /* Spectrocam Xenon Lamp */
+#endif /* !SALONEINSTLIB*/
icxIT_ODtemp = 15, /* Daylight at specified temperature */
icxIT_Dtemp = 16, /* 15:2004 Daylight at specified temperature */
-#endif /* !SALONEINSTLIB*/
icxIT_OPtemp = 17, /* Planckian at specified temperature */
icxIT_Ptemp = 18 /* 15:2004 Planckian at specified temperature */
} icxIllumeType;
@@ -317,10 +339,10 @@ struct _xsp2cie {
xsp2cie *new_xsp2cie(
icxIllumeType ilType, /* Observer Illuminant to use */
- xspect *custIllum,
+ xspect *custIllum, /* Custom illuminant if ilType == icxIT_custom */
icxObserverType obType, /* Observer */
- xspect custObserver[3],
+ xspect custObserver[3], /* Custom observer if obType == icxOT_custom */
icColorSpaceSignature rcs, /* Return color space, icSigXYZData or D50 icSigLabData */
/* ** Must be icSigXYZData if SALONEINSTLIB ** */
icxClamping clamp /* NZ to clamp XYZ/Lab to be +ve */
@@ -334,6 +356,7 @@ xsp2cie *new_xsp2cie(
/* An observer type can be chosen for interpretting the spectrum of the input and */
/* the illuminant. */
/* Return -1.0 on erorr */
+/* (Faster, slightly less accurate version of icx_XYZ2ill_ct()) */
double icx_XYZ2ill_ct2(
double txyz[3], /* If not NULL, return the XYZ of the locus temperature */
icxIllumeType ilType, /* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
@@ -347,6 +370,7 @@ int viscct /* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
/* An observer type can be chosen for interpretting the spectrum of the input and */
/* the illuminant. */
/* Return xyz[0] = -1.0 on erorr */
+/* (Faster, slightly less accrurate alternative to standardIlluminant()) */
void icx_ill_ct2XYZ(
double xyz[3], /* Return the XYZ value */
icxIllumeType ilType, /* Type of illuminant, icxIT_[O]Dtemp or icx[O]IT_Ptemp */
@@ -391,6 +415,86 @@ xslpoly *chrom_locus_poligon(icxLocusType locus_type, icxObserverType obType, in
/* Return 1 if outside locus */
int icx_outside_spec_locus(xslpoly *p, double xyz[3]);
+/* ------------------------------------------------- */
+
+/* Given a reflectance/transmittance spectrum, */
+/* an illuminant definition and an observer model, return */
+/* the XYZ value for that spectrum. */
+/* Return 0 on sucess, 1 on error */
+/* (One shot version of xsp2cie etc.) */
+int icx_sp2XYZ(
+double xyz[3], /* Return XYZ value */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+icxIllumeType ilType, /* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
+double ct, /* Input temperature in degrees K */
+xspect *custIllum, /* Optional custom illuminant */
+xspect *sp /* Spectrum to be converted */
+);
+
+/* ------------------------------------------------- */
+/* Color temperature and CRI */
+
+/* Given an illuminant definition and an observer model, return */
+/* the normalised XYZ value for that spectrum. */
+/* Return 0 on sucess, 1 on error */
+/* (One shot version of xsp2cie etc.) */
+int icx_ill_sp2XYZ(
+double xyz[3], /* Return XYZ value with Y == 1 */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+icxIllumeType ilType, /* Type of illuminant */
+double temp, /* Input temperature in degrees K */
+xspect *custIllum); /* Optional custom illuminant */
+
+/* Given a choice of temperature dependent illuminant (icxIT_[O]Dtemp or icxIT_[O]Ptemp), */
+/* return the closest correlated color temperature to the given spectrum or XYZ. */
+/* An observer type can be chosen for interpretting the spectrum of the input and */
+/* the illuminant. */
+/* Return -1 on erorr */
+double icx_XYZ2ill_ct(
+double txyz[3], /* If not NULL, return the XYZ of the black body temperature */
+icxIllumeType ilType, /* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+double xyz[3], /* Input XYZ value, NULL if spectrum intead */
+xspect *insp0, /* Input spectrum value, NULL if xyz[] instead */
+int viscct); /* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
+
+/* Compute the CIE1995 CRI: Ra */
+/* Return < 0.0 on error */
+/* If invalid is not NULL, set it to nz if CRI */
+/* is invalid because the sample is not white enough. */
+double icx_CIE1995_CRI(
+int *invalid, /* if not NULL, set to nz if invalid */
+double cris[14], /* If not NULL, return the TCS01-14 CRI's */
+xspect *sample /* Illuminant sample to compute CRI of */
+);
+
+/* Compute the EBU TLCI-2012 Qa */
+/* Return < 0.0 on error */
+/* If invalid is not NULL, set it to nz if TLCI */
+/* is invalid because the sample is not white enough. */
+double icx_EBU2012_TLCI(
+int *invalid, /* if not NULL, set to nz if invalid */
+xspect *sample /* Illuminant sample to compute TLCI of */
+);
+
+/* Return the maximum 24 hour exposure in seconds. */
+/* Limit is 8 hours */
+/* Returns -1 if the source sample doesn't go down to at least 350 nm */
+double icx_ARPANSA_UV_exp(
+xspect *sample /* Illuminant sample to compute UV_exp of */
+);
+
+/* Return a polinomial aproximation of CCT */
+double aprox_CCT(double xyz[3]);
+
+/* Aproximate x,y from CCT using Kim et al's cubic spline. */
+/* Invalid < 1667 and > 25000 */
+/* (Doesn't set Yxy[0]) */
+void aprox_plankian(double Yxy[3], double ct);
+
/* --------------------------- */
/* Density and other functions */
@@ -447,58 +551,6 @@ double desat /* 0.0 = full saturation, 1.0 = white */
);
-/* Given an illuminant definition and an observer model, return */
-/* the normalised XYZ value for that spectrum. */
-/* Return 0 on sucess, 1 on error */
-int icx_ill_sp2XYZ(
-double xyz[3], /* Return XYZ value with Y == 1 */
-icxObserverType obType, /* Observer */
-xspect custObserver[3], /* Optional custom observer */
-icxIllumeType ilType, /* Type of illuminant */
-double temp, /* Input temperature in degrees K */
-xspect *custIllum); /* Optional custom illuminant */
-
-
-/* Given a choice of temperature dependent illuminant (icxIT_[O]Dtemp or icxIT_[O]Ptemp), */
-/* return the closest correlated color temperature to the given spectrum or XYZ. */
-/* An observer type can be chosen for interpretting the spectrum of the input and */
-/* the illuminant. */
-/* Return -1 on erorr */
-double icx_XYZ2ill_ct(
-double txyz[3], /* If not NULL, return the XYZ of the black body temperature */
-icxIllumeType ilType, /* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
-icxObserverType obType, /* Observer */
-xspect custObserver[3], /* Optional custom observer */
-double xyz[3], /* Input XYZ value, NULL if spectrum intead */
-xspect *insp0, /* Input spectrum value, NULL if xyz[] instead */
-int viscct); /* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
-
-/* Compute the CIE1995 CRI: Ra */
-/* Return < 0.0 on error */
-/* If invalid is not NULL, set it to nz if CRI */
-/* is invalid because the sample is not white enough. */
-double icx_CIE1995_CRI(
-int *invalid, /* if not NULL, set to nz if invalid */
-double cris[14], /* If not NULL, return the TCS01-14 CRI's */
-xspect *sample /* Illuminant sample to compute CRI of */
-);
-
-/* Compute the EBU TLCI-2012 Qa */
-/* Return < 0.0 on error */
-/* If invalid is not NULL, set it to nz if TLCI */
-/* is invalid because the sample is not white enough. */
-double icx_EBU2012_TLCI(
-int *invalid, /* if not NULL, set to nz if invalid */
-xspect *sample /* Illuminant sample to compute TLCI of */
-);
-
-/* Return the maximum 24 hour exposure in seconds. */
-/* Limit is 8 hours */
-/* Returns -1 if the source sample doesn't go down to at least 350 nm */
-double icx_ARPANSA_UV_exp(
-xspect *sample /* Illuminant sample to compute UV_exp of */
-);
-
#endif /* !SALONEINSTLIB*/
#ifdef __cplusplus
diff --git a/yajl/yajl_common.h b/yajl/yajl_common.h
index 95a5ab7..3558c7d 100644
--- a/yajl/yajl_common.h
+++ b/yajl/yajl_common.h
@@ -53,6 +53,7 @@ extern "C" {
#endif
// Create a cross platform 64 bit int type "longlong" - GWG
+#ifndef NUMLIB_H
#if (__STDC_VERSION__ >= 199901L) /* C99 */
@@ -93,27 +94,44 @@ typedef __int64 longlong;
/* LLP64 and LP64 models, but won't work with ILP64 which needs int32 */
#ifdef __GNUC__
-
-typedef long long longlong;
-
-# define PF64PREC "ll" /* printf format precision specifier */
-# define CF64PREC "LL" /* Constant precision specifier */
-
-# ifndef LLONG_MIN
-# define LLONG_MIN (-LLONG_MAX-1)
-# endif
-# ifndef LLONG_MAX
-# define LLONG_MAX __LONG_LONG_MAX__
-# endif
-# ifndef ULLONG_MAX
-# define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
-# endif
-
+# ifdef __LP64__ /* long long could be 128 bit ? */
+ typedef long longlong;
+# define PF64PREC "l" /* printf format precision specifier */
+# define CF64PREC "L" /* Constant precision specifier */
+# ifndef LLONG_MAX
+# define LLONG_MAX __LONG_MAX__
+# endif
+# ifndef LLONG_MIN
+# define LLONG_MIN (-LLONG_MAX-1)
+# endif
+# ifndef ULLONG_MAX
+# define ULLONG_MAX (LLONG_MAX * 2UL + 1)
+# endif
+# else /* long could be 32 bits */
+ typedef long long longlong;
+# define PF64PREC "ll" /* printf format precision specifier */
+# define CF64PREC "LL" /* Constant precision specifier */
+# ifndef LLONG_MAX
+# define LLONG_MAX __LONG_LONG_MAX__
+# endif
+# ifndef LLONG_MIN
+# define LLONG_MIN (-LLONG_MAX-1)
+# endif
+# ifndef ULLONG_MAX
+# define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
+# endif
+# endif /* !__LP64__ */
#endif /* __GNUC__ */
#endif /* !_MSC_VER */
#endif /* !__STDC_VERSION__ */
+#else /* !NUMLIB_H */
+
+typedef INR64 longlong ;
+
+#endif /* !NUMLIB_H */
+
/** pointer to a malloc function, supporting client overriding memory
* allocation routines */
typedef void * (*yajl_malloc_func)(void *ctx, size_t sz);
diff --git a/yajl/yajl_gen.c b/yajl/yajl_gen.c
index 17ce003..450b898 100644
--- a/yajl/yajl_gen.c
+++ b/yajl/yajl_gen.c
@@ -266,7 +266,7 @@ yajl_gen_integer(yajl_gen g, longlong number)
{
char i[32];
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
- sprintf(i, "%lld", number);
+ sprintf(i, "%" PF64PREC "d", number);
g->print(g->ctx, i, (unsigned int)strlen(i));
APPENDED_ATOM;
FINAL_NEWLINE;