From f7208b7b8d6ccf56ffb3230b87554ace5411f4f6 Mon Sep 17 00:00:00 2001 From: Septs Date: Fri, 24 Dec 2021 00:00:00 +0000 Subject: [PATCH] v2.3.0 --- Jambase | 37 +-- Jamtop | 2 +- Readme.txt | 6 +- doc/ArgyllDoc.html | 418 ++++++++++++++++++++++++++++++++-- doc/ChangesSummary.html | 47 +++- doc/Environment.html | 55 +++-- doc/FWA.html | 26 ++- doc/Installing_MSWindows.html | 9 +- doc/instruments.html | 90 +++++++- doc/scanin.html | 92 ++++++-- doc/spotread.html | 183 ++++++++++++--- gamut/gammap.txt | 6 +- gamut/gamut.c | 2 +- gamut/viewgam.c | 3 +- h/aconfig.h | 4 +- log.txt | 41 +++- numlib/numsup.h | 2 +- plot/plot.h | 6 +- profile/cxf2ti3.c | 64 ++++-- profile/profout.c | 2 +- scanin/scanrd.c | 70 +++--- spectro/Jamfile | 9 +- spectro/Jamfile.SA | 32 +++ spectro/Makefile.SA | 3 +- spectro/afiles | 1 + spectro/ccxxmake.c | 2 +- spectro/chartread.c | 2 +- spectro/colorhug.c | 13 ++ spectro/colorhug.h | 1 + spectro/conv.c | 155 ++++--------- spectro/dispcal.c | 2 +- spectro/dispread.c | 2 +- spectro/dispwin.c | 33 ++- spectro/ex1.c | 12 + spectro/huey.c | 14 +- spectro/huey.h | 1 + spectro/i1d3.c | 127 ++++++++--- spectro/i1d3.h | 4 +- spectro/i1disp.c | 15 +- spectro/i1disp.h | 3 +- spectro/i1pro.c | 2 +- spectro/i1pro3_imp.c | 43 +++- spectro/i1pro_imp.h | 2 +- spectro/inst.c | 1 + spectro/inst.h | 1 + spectro/instappsup.c | 14 +- spectro/instappsup.h | 6 +- spectro/instlib.ksh | 14 +- spectro/kleink10.c | 11 + spectro/linear.cal | 2 +- spectro/sa_conv.c | 29 +++ spectro/sa_conv.h | 7 + spectro/specbos.c | 21 +- spectro/specbos.h | 3 +- spectro/spotread.c | 31 ++- spectro/spyd2.c | 12 + spectro/spydX.c | 24 +- spectro/spydX.h | 6 +- spectro/ss.c | 20 +- spectro/ss.h | 2 + spectro/strange.cal | 2 +- spectro/usbio.c | 33 ++- spectro/usbio_lx.c | 8 +- spectro/usbio_nt.c | 2 +- usb/55-Argyll.rules | 5 +- usb/ArgyllCMS.cat | Bin 3719 -> 3719 bytes usb/ArgyllCMS_x64.cat | Bin 3703 -> 3703 bytes xicc/Jamfile | 3 +- xicc/afiles | 1 + xicc/bluelin.c | 407 +++++++++++++++++++++++++++++++++ xicc/cam02.c | 132 ++++++++++- xicc/cam02.h | 3 +- xicc/cam02test.c | 24 +- 73 files changed, 2053 insertions(+), 414 deletions(-) create mode 100644 spectro/Jamfile.SA create mode 100644 xicc/bluelin.c diff --git a/Jambase b/Jambase index a24c65e7..f58f343c 100644 --- a/Jambase +++ b/Jambase @@ -430,13 +430,15 @@ if $(NT) MINGW64_LIB32 = $(MINGW)/mingw/lib32 ; } else { ECHO "Compiler is MingW for 32 bit target" ; + TPFX1 = "" ; # Some tools + TPFX2 = "" ; # Rest of tools } - # Basic C/C++ tools AR ?= $(TPFX2)ar rusc ; AS ?= $(TPFX2)as ; CC ?= $(TPFX1)gcc ; +echo "CC = " $(CC) ; CCFLAGS ?= -DNT -mwin32 -pipe ; C++ ?= $(CC) ; C++FLAGS ?= $(CCFLAGS) ; @@ -2072,19 +2074,19 @@ rule _JamInclude if $(_JAMINCLUDE_PEER) != "true" { # Incorporate this levels extra flags & header paths into the base - P_ASFLAGS += $(ASFLAGS) ; - P_CCFLAGS += $(CCFLAGS) ; - P_C++FLAGS += $(C++FLAGS) ; - P_LINKFLAGS += $(LINKFLAGS) ; - P_SHLINKFLAGS += $(SHLINKFLAGS) ; - P_HDRS = [ NormPaths $(HDRS) ] $(P_HDRS) ; - P_DEFINES += $(DEFINES) ; - P_LINKOBJS = [ NormPaths $(LINKOBJS) ] $(P_LINKOBJS) ; - P_LINKLIBS = [ NormPaths $(LINKLIBS) ] $(P_LINKLIBS) ; - P_LINKSHLIBS = [ NormPaths $(LINKSHLIBS) ] $(P_LINKSHLIBS) ; - P_SHLINKOBJS = [ NormPaths $(SHLINKOBJS) ] $(P_SHLINKOBJS) ; - P_SHLINKLIBS = [ NormPaths $(SHLINKLIBS) ] $(P_SHLINKLIBS) ; - P_SHLINKSHLIBS = [ NormPaths $(SHLINKSHLIBS) ] $(P_SHLINKSHLIBS) ; + P_ASFLAGS += $(ASFLAGS) ; ASFLAGS = "" ; + P_CCFLAGS += $(CCFLAGS) ; CCFLAGS = "" ; + P_C++FLAGS += $(C++FLAGS) ; C++FLAGS = "" ; + P_LINKFLAGS += $(LINKFLAGS) ; LINKFLAGS = "" ; + P_SHLINKFLAGS += $(SHLINKFLAGS) ; SHLINKFLAGS = "" ; + P_HDRS = [ NormPaths $(HDRS) ] $(P_HDRS) ; HDRS = "" ; + P_DEFINES += $(DEFINES) ; DEFINES = "" ; + P_LINKOBJS = [ NormPaths $(LINKOBJS) ] $(P_LINKOBJS) ; LINKOBJS = "" ; + P_LINKLIBS = [ NormPaths $(LINKLIBS) ] $(P_LINKLIBS) ; LINKLIBS = "" ; + P_LINKSHLIBS = [ NormPaths $(LINKSHLIBS) ] $(P_LINKSHLIBS) ; LINKSHLIBS = "" ; + P_SHLINKOBJS = [ NormPaths $(SHLINKOBJS) ] $(P_SHLINKOBJS) ; SHLINKOBJS = "" ; + P_SHLINKLIBS = [ NormPaths $(SHLINKLIBS) ] $(P_SHLINKLIBS) ; SHLINKLIBS = "" ; + P_SHLINKSHLIBS = [ NormPaths $(SHLINKSHLIBS) ] $(P_SHLINKSHLIBS) ; SHLINKSHLIBS = "" ; # Set parent flags no existing parent flags if ! $(P_PREF_ASFLAGS) { @@ -3383,6 +3385,7 @@ rule MainFromObjects #Echo "MainFromObjects LINKFLAGS = '" $(LINKFLAGS) "' and P_LINKFLAGS ='" $(P_LINKFLAGS) "'" ; #Echo " PREF_LINKFLAGS = '" $(PREF_LINKFLAGS) "' and P_PREF_LINKFLAGS ='" $(P_PREF_LINKFLAGS) "'" ; +#Echo " pref_linkflags = '" $(pref_linkflags) "'" ; if $(LINKFLAGS) || $(P_LINKFLAGS) || $(PREF_LINKFLAGS) || $(P_PREF_LINKFLAGS) { local pref_linkflags = $(P_PREF_LINKFLAGS) ; @@ -3643,6 +3646,8 @@ rule Object switch $(_s:S) { case .asm : As_ $(_t) : $(_s) ; + case .s : As_ $(_t) : $(_s) ; + case .S : As_ $(_t) : $(_s) ; case .c : Cc_ $(_t) : $(_s) ; @@ -3662,8 +3667,6 @@ rule Object Cc_ $(_t) : $(_c) ; } - case .s : As_ $(_t) : $(_s) ; - case .y : { local _c = $(_t:S=$(YACCGEN)) ; CopyTarget $(_c) : $(_t) ; # Transfer LOCATE, SEARCH, NOMLOC @@ -4140,7 +4143,7 @@ actions together ArchiveArchive rm -rf .jamArchiveArchive$PPID } -actions As +actions As_ { $(AS) $(ASFLAGS) $(ASHDRS) -o $(<) $(>) } diff --git a/Jamtop b/Jamtop index a6207e91..45a67cfe 100644 --- a/Jamtop +++ b/Jamtop @@ -46,7 +46,7 @@ USE_VTPGLUT = false ; USE_PRINTER = false ; # enable CMF Measurement device and accessory support (if present) -USE_CMFM = false ; +USE_CMFM = true ; # Use ArgyllCMS version of libusb (deprecated - don't use) USE_LIBUSB = false ; # [false] diff --git a/Readme.txt b/Readme.txt index f40915df..8b852689 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,8 +1,8 @@ -Argyll CMS README file - Version 2.2.1 +Argyll CMS README file - Version 2.3.0 -------------------------------------- -Date: 17th September 2021 +Date: 24th December 2021 Author: Graeme Gill Introduction @@ -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 2.2.1, a bug fix update to the last release V2.2.0. +This is Version 2.3.0, a bug fix and feature change update to the last release V2.2.1. 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/doc/ArgyllDoc.html b/doc/ArgyllDoc.html index f1e75f83..70ebfc63 100644 --- a/doc/ArgyllDoc.html +++ b/doc/ArgyllDoc.html @@ -10,9 +10,9 @@ Argyll Documentation Top -

ArgyllCMS documentation index (V2.2.1)
+

ArgyllCMS documentation index (V2.3.0)

- Date:   17th September 2021
+ Date:   24th December 2021
Author: Graeme Gill

Introduction

ArgyllCMS is an ICC compatible color management system, available as @@ -35,13 +35,13 @@

Introduction

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 2.2.1, a bug fix update to the last release - V2.2.0. The first public release of icclib was in November 1998, - and of ArgyllCMS was in October 2000. Code development commenced - in 1995. See Changes Summary - for an overview of changes since the last release. Changes between - revisions is detailed in the log.txt file that accompanies - the source code.

+

This is Version 2.3.0, a bug fix and feature change update to the + last release V2.2.1. The first public release of icclib was in + November 1998, and of ArgyllCMS was in October 2000. Code + development commenced in 1995. See Changes + Summary for an overview of changes since the last release. + Changes between revisions is detailed in the log.txt file + that accompanies the source code.

The latest source code is available from here.

@@ -169,6 +169,9 @@

An Introduction to Color + + + @@ -331,6 +334,9 @@

+ + + @@ -385,6 +391,9 @@

+ + + @@ -509,6 +518,9 @@

+ + + @@ -610,6 +622,9 @@

+ + + @@ -779,6 +794,9 @@

+ + + @@ -942,6 +960,9 @@

+ + + @@ -1104,6 +1125,9 @@

+ + + @@ -1268,6 +1292,9 @@

+ + + @@ -1430,6 +1457,9 @@

+ + + @@ -1592,6 +1622,9 @@

+ + + @@ -1627,19 +1660,14 @@

built in laptop Huey display colorimeter.
   
Eye-One Display 3                 -         - Xrite i1 DisplayPro, DisplayPro Plus - and ColorMunki Display
+         - i1 DisplayPro, DisplayPro Plus and + ColorMunki Display/i1Display Studio
                                                -           [ The OEM - i1Display Pro, NEC SpectraSensor Pro,
-                   -                   -                   -        Quato Silver Haze 3 OEM,  HP - DreamColor, Wacom i1d3 and Toshiba TPA-1 are also reported to work.]
+           [ Other branded + i1d3's are also reported to work.]
    i1Pro2                              @@ -1649,6 +1677,9 @@

+ + + - spot and "swipe" reflective/emissive spectrometer.
    i1Pro3 and i1Pro3 @@ -1657,6 +1688,9 @@

+ + + Plus
                 @@ -1665,6 +1699,9 @@

+ + + - spot and "swipe" reflective/emissive spectrometer.

@@ -1849,6 +1886,9 @@

+ + + @@ -2012,6 +2052,9 @@

+ + + @@ -2184,6 +2227,9 @@

+ + + @@ -2349,6 +2395,9 @@

+ + + @@ -2518,6 +2567,9 @@

+ + + @@ -2704,6 +2756,9 @@

+ + + @@ -2758,6 +2813,9 @@

+ + + @@ -2829,6 +2887,9 @@

+ + + @@ -2880,6 +2941,9 @@

+ + + @@ -3157,6 +3221,9 @@

Graphic + + + @@ -3635,6 +3708,9 @@

Graphic + + + @@ -3808,6 +3884,9 @@

Main + + + @@ -3985,6 +4064,9 @@

Main + + + @@ -4148,6 +4230,9 @@

Main + + + @@ -4311,6 +4396,9 @@

Main + + + @@ -4477,6 +4565,9 @@

Main + + + @@ -4640,6 +4731,9 @@

Main + + + @@ -4954,6 +5048,9 @@

Creating test targets for profiling or print calibration
+ + + @@ -5118,6 +5215,9 @@

Creating test targets for profiling or print calibration
+ + + @@ -5282,6 +5382,9 @@

Creating test targets for profiling or print calibration
+ + + @@ -5448,6 +5551,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -5613,6 +5719,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -5777,6 +5886,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -5941,6 +6053,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -6110,6 +6225,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -6278,6 +6396,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -6443,6 +6564,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -6607,6 +6731,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -6772,6 +6899,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -6800,6 +6930,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -6964,6 +7097,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -7058,6 +7194,9 @@

Obtaining test results for profiling or print calibration
+ + + @@ -7223,6 +7362,9 @@

Creating Device Profiles

+ + + @@ -7387,6 +7529,9 @@

Creating Device Profiles

+ + + @@ -7551,6 +7696,9 @@

Creating Device Profiles

+ + + @@ -7716,6 +7864,9 @@

Creating Device Link Profiles

+ + + @@ -7882,6 +8033,9 @@

Converting colors or applying print calibration
+ + + @@ -8046,6 +8200,9 @@

Converting colors or applying print calibration
+ + + @@ -8209,6 +8366,9 @@

Converting colors or applying print calibration
+ + + @@ -8373,6 +8533,9 @@

Converting colors or applying print calibration
+ + + @@ -8537,6 +8700,9 @@

Converting colors or applying print calibration
+ + + @@ -8701,6 +8867,9 @@

Converting colors or applying print calibration
+ + + @@ -8873,6 +9042,9 @@

Creating gamut views

+ + + @@ -9036,6 +9208,9 @@

Creating gamut views

+ + + @@ -9200,6 +9375,9 @@

Creating gamut views

+ + + @@ -9366,6 +9544,9 @@

Diagnostic and test tools
+ + + @@ -9529,6 +9710,9 @@

Diagnostic and test tools
+ + + @@ -9692,6 +9876,9 @@

Diagnostic and test tools
+ + + @@ -9854,6 +10041,9 @@

Diagnostic and test tools
+ + + @@ -10021,6 +10211,9 @@

Diagnostic and test tools
+ + + @@ -10183,6 +10376,9 @@

Diagnostic and test tools
+ + + @@ -10289,6 +10485,9 @@

Diagnostic and test tools
+ + + @@ -10452,6 +10651,9 @@

Diagnostic and test tools
+ + + @@ -10616,6 +10818,9 @@

Other Tools

+ + + @@ -10782,6 +10987,9 @@

Other Tools

+ + + @@ -10798,6 +11006,9 @@

Other Tools

monospace;">       Extract + + + or insert a 'vcgt' calibration tag from/into an ICC profile.
Other Tools

+ + + @@ -11036,6 +11250,9 @@

Other Tools

+ + + @@ -11202,6 +11419,9 @@

Main Tools + + + @@ -11365,6 +11585,9 @@

Main Tools + + + @@ -11529,6 +11752,9 @@

Main Tools + + + @@ -11693,6 +11919,9 @@

Main Tools + + + @@ -11856,6 +12085,9 @@

Main Tools + + + @@ -12021,6 +12253,9 @@

Main Tools + + + @@ -12184,6 +12419,9 @@

Main Tools + + + @@ -12348,6 +12586,9 @@

Main Tools + + + @@ -12380,6 +12621,9 @@

Main Tools + + + @@ -12547,6 +12791,9 @@

Main Tools + + + @@ -12711,6 +12958,9 @@

Main Tools + + + @@ -12876,6 +13126,9 @@

Main Tools + + + @@ -13044,6 +13297,9 @@

Main Tools + + + @@ -13208,6 +13464,9 @@

Main Tools + + + @@ -13371,6 +13630,9 @@

Main Tools + + + @@ -13534,6 +13796,9 @@

Main Tools + + + @@ -13697,6 +13962,9 @@

Main Tools + + + @@ -13861,6 +14129,9 @@

Main Tools + + + @@ -14024,6 +14295,9 @@

Main Tools + + + @@ -14187,6 +14461,9 @@

Main Tools + + + @@ -14198,6 +14475,9 @@

Main Tools style="font-family: monospace;">       + + + Extract or insert a 'vcgt' calibration tag from/into an ICC profile.
@@ -14357,6 +14637,9 @@

Main Tools + + + @@ -14524,6 +14807,9 @@

Main Tools + + + @@ -14592,6 +14878,9 @@

Main Tools + + + @@ -14756,6 +15045,9 @@

Main Tools + + + @@ -14919,6 +15211,9 @@

Main Tools + + + @@ -15083,6 +15378,9 @@

Main Tools + + + @@ -15251,6 +15549,9 @@

Main Tools + + + @@ -15414,6 +15715,9 @@

Main Tools + + + @@ -15578,6 +15882,9 @@

Main Tools + + + @@ -15747,6 +16054,9 @@

Main Tools + + + @@ -15911,6 +16221,9 @@

Main Tools + + + @@ -16076,6 +16389,9 @@

Main Tools + + + @@ -16241,6 +16557,9 @@

Main Tools + + + @@ -16403,6 +16722,9 @@

Main Tools + + + @@ -16566,6 +16888,9 @@

Main Tools + + + @@ -16729,6 +17054,9 @@

Main Tools + + + @@ -16893,6 +17221,9 @@

Main Tools + + + @@ -17056,6 +17387,9 @@

Main Tools + + + @@ -17220,6 +17554,9 @@

Main Tools + + + @@ -17388,6 +17725,9 @@

Main Tools + + + @@ -17553,6 +17893,9 @@

Main Tools + + + @@ -17717,6 +18060,9 @@

Main Tools + + + @@ -17908,6 +18254,9 @@

File + + + @@ -18070,6 +18419,9 @@

File + + + @@ -18232,6 +18584,9 @@

File + + + @@ -18398,6 +18753,9 @@

File + + + @@ -18561,6 +18919,9 @@

File + + + @@ -18723,6 +19084,9 @@

File + + + @@ -18893,6 +19257,9 @@

File + + + @@ -19055,6 +19422,9 @@

File + + + @@ -19217,6 +19587,9 @@

File + + + @@ -19379,6 +19752,9 @@

File + + + @@ -19541,6 +19917,9 @@

File + + + @@ -19708,6 +20087,9 @@

File + + + diff --git a/doc/ChangesSummary.html b/doc/ChangesSummary.html index 9bb26f27..d91f899f 100644 --- a/doc/ChangesSummary.html +++ b/doc/ChangesSummary.html @@ -17,24 +17,51 @@

Summary of Argyll CMS Changes since last release

For a complete and more detailed list of changes, please see the log.txt file.

+

[V2.2.1 -> V2.3.0] 24th December 2021

+
    +
  • Fixed spotread -YL (i1Pro1/2 lamp remediation) to function + even if calibration is impossible due to the white reference + being out of tolerance.
    +
  • +
  • Fix SpyderX faulty initial black calibration (it was asking + for  calibration every measurement).
  • +
  • Added icomuf_reset_before_close flag for SpyderX, as some + versions of the instrument have been reported to lock up after + use.
  • +
  • Modified the ArgyllCMS CIECAM02 implementation to include a + blue hue linearization tweak, to improve the "blue goes purple" + effect when gamut mapping or clipping highly saturated blues to + smaller gamuts.
  • +
  • Added spotread -Y y option that forces the listing of + instrument specific display calibrations in the usage, even for + serial instruments.
  • +
  • Removed native i1d3 C6 instrument support as a favor to + X-Rite. Anybody adversely affected should contact me (Graeme + Gill).
  • +
  • Improved cxf2ti3 so that it should cope with XML that uses + "Colour" spelling rather than "Color".
  • +
  • Added I1D3_ESCAPE environment variable to allow a user to + potentialy use any current or future OEM coded i1d3 instrument.
    +
  • +

[V2.2.0 -> V2.2.1] 17th September 2021

    -
  • * Added support for Christophe Mtairie's Mini Digital Target +
  • Added support for Christophe Mtairie's Mini Digital Target with CMP_DT_mini.cht
  • -
  • * Fix inconsistency between .ti3 documentation of +
  • Fix inconsistency between .ti3 documentation of NORMALIZED_TO_Y_100 tag behavior and profile/profin.c code.
  • -
  • * Improved cxf2ti3 so that it truncates trailing spaces on the +
  • Improved cxf2ti3 so that it truncates trailing spaces on the names of patch id's. This caused scanin to ignore patches with such trailing spaces, omitting them from the resulting .ti3 file.
  • -
  • * Added iccvcgt utility for extracting or inserting a 'vcgt' - tag from or into an ICC profile.
  • -
  • * Fix bug in applycal.c introduced in 2.2.0 - crashes when +
  • Added iccvcgt utility for extracting or inserting a 'vcgt' tag + from or into an ICC profile.
  • +
  • Fix bug in applycal.c introduced in 2.2.0 - crashes when existing ICC curves are not 256 step LUTs.
  • -
  • * Removed OS X hidio device Release - returned error on recent +
  • Removed OS X hidio device Release - returned error on recent OS X versions.
  • -
  • * Fix bug in dispwin on OS X that randomly causes crash on - exit by removing release calls.
  • +
  • Fix bug in dispwin on OS X that randomly causes crash on exit + by removing release calls.

[V2.1.2 -> V2.2.0] 3rd May 2021

    @@ -1369,6 +1396,7 @@

    [V1.0.2 -> V1.0.3] 3rd September 2008
    + for systems with > 3Gig Ram. @@ -1439,6 +1467,7 @@

    [V1.0.1 -> V1.0.2] 19th August 2008
    + and memory usage issues. diff --git a/doc/Environment.html b/doc/Environment.html index 40f61570..9d7299bc 100644 --- a/doc/Environment.html +++ b/doc/Environment.html @@ -63,11 +63,11 @@

    Environment variables


    Normally Argylls tools expect that they are directly interacting with a user, and use a couple of - techniques for communicating with them through the command line. - One is to output progress information by re-writing the same - display line by using a Carriage Return rather than a Line Feed at - the end of each line. Another is to allow a single key stroke to - trigger an action or interrupt operations.
    + techniques for communicating with them through the console and + command line. One is to output progress information by re-writing + the same display line by using a Carriage Return rather than a + Line Feed at the end of each line. Another is to allow a single + key stroke to trigger an action or interrupt operations.

    If the ARGYLL_NOT_INTERACTIVE environment variable is set, then:
    @@ -75,20 +75,21 @@

    Environment variables

        A Line Feed will be added to the end of each progress line.

    -     Any time it would wait for a single keystroke - input, it will instead wait for and read the next character from - stdin.
    -     To facilitate flushing stdin, any return or - line feed characters will be ignored, so a character other than - return or line feed must be used to trigger activity.
    +     Any time it would wait for a single console + keystroke input, it will instead wait for and read the next + character and a return from stdin.
    +     The first character read will be used, and any + following return characters ignored.

    -     Note that while a reading is being made, a - character input can abort the reading, just as with normal - interactive mode.
    +     Note that while a measurement is being made, a + character input (i.e. stdin character followed by a return) can + abort the reading, just as with normal interactive mode.

    -     Note that on MSWin systems, the character and - return or line feed characters must be written to stdin in a - single operation (i.e. testing ARGYLL_NOT_INTERACTIVE  +     On MSWin systems, the character and return or + line feed characters must be written to stdin in a single + operation (i.e. testing ARGYLL_NOT_INTERACTIVE  + + @@ -105,7 +106,7 @@

    Environment variables

    mode manually will probably fail, because the character and - return get split up.)
    + return get split up unless you are very fast at typing them.)

    ARGYLL_3D_DISP_FORMAT
    @@ -131,6 +132,8 @@

    Environment variables

    + +
    or X3DOM, which will result in .wrl, .x3d and .x3d.html files respectively. See 3d @@ -152,6 +155,8 @@

    Environment variables

    + + Viewing Format
    .
    @@ -200,6 +205,8 @@

    Environment variables

    + + delay of 200 msec is allowed between changing a patch color in software, and that change appearing in the displayed color itself. @@ -234,6 +241,8 @@

    Environment variables

    + + variable, ie. ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS=400 would set a 400 msec minimum delay.
    @@ -388,6 +397,8 @@

    Environment variables

    + + for more details.)Environment variables

+ + environment @@ -432,6 +447,8 @@

Environment variables

+ + 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 @@ -591,6 +608,8 @@

Environment variables

+ + Directory Specification, and uses the XDG_CACHE_HOME environment diff --git a/doc/FWA.html b/doc/FWA.html index e83a64f8..d251b6e0 100644 --- a/doc/FWA.html +++ b/doc/FWA.html @@ -202,15 +202,17 @@

Using FWA compensation for single, general use profiles

specifications, FWA compensation should ideally be used when building a interchangeable ICC profile, by selecting the D50 illuminant, and the 1931_2 observer model (ISO 13655:2009 M1). Note - however that this is likely to make profiles less - interchangeable rather than more, since few if any other profiles - will represent the appearance under real D50, since few if any - instruments use a real D50 illuminant that will trigger the correct - level of FWA response, and few if any other packages will compensate - for the differences in FWA activity between the instrument - illuminant used and real D50 (ie. most instruments are actually - returning  ISO 13655:2009 M0 measurements).
+ interchangeable rather than more, since few if any profiles made + with older instruments will represent the appearance under real D50, + since few if any of those instruments use a real D50 illuminant that + will trigger the correct level of FWA response, and few if any other + packages will compensate for the differences in FWA activity between + the instrument illuminant used and real D50 (ie. most instruments + return M0 measurements by default, and older instruments are + generally not capable of M1 measurement).

Similarly, the effects of viewing the media in an environment with a UV filter fitted over the D50 illuminant can be simulated by using @@ -234,8 +236,8 @@

Measuring the illuminant

containing FWA.

FWA myths

- Amongst the user (and to some degree) vendor community, there is a - widely held belief that the solution to fluorescent whitener + Amongst the user (and to some degree) vendor community, there has + been a widely held belief that the solution to fluorescent whitener affecting color profiles is to simply use a UV filter fitted instrument. Exactly what the origin of the legend is, is hard to tell. Possibly it is a misinterpretation of the  ANSI @@ -253,8 +255,8 @@

Instrument UV filters

Note that to be able to measure the FWA in the paper, the instrument has to be able to trigger Fluorescence, which it cannot do if it is fitted with a UV filter, or uses a light source that emits no UV - (e.g. a white LED). So UV excluded instruments are not suitable for - use with FWA compensation.
+ (e.g. a normal white LED). So UV excluded instruments are not + suitable for use with FWA compensation.



diff --git a/doc/Installing_MSWindows.html b/doc/Installing_MSWindows.html index 72709ba6..52a7000f 100644 --- a/doc/Installing_MSWindows.html +++ b/doc/Installing_MSWindows.html @@ -143,6 +143,7 @@

USB Instruments:

+ Virtual COM Port Drivers (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 JETI specbos 1511, @@ -150,6 +151,7 @@

USB Instruments:

+ 1501
use.

Jump to your operating system version:
@@ -224,8 +226,8 @@

USB Instruments:

Driver:
    Settings -> Power -> Hold Shift Key down and click - "Restart" -> Troubleshoot -> Advanced Options -> Startup - Settings -> Restart ->
+ "Restart", wait for restart then -> Troubleshoot -> Advanced + Options -> Startup Settings -> Restart ->
    (After Reboot) -> Disable Driver Signature Enforcement" (number 7 on the list)
    (After system starts, Plug in instrument)
@@ -322,6 +324,7 @@

USB Instruments:

+ Argyll drivers with existing OEM drivers:

If you currently have applications other than Argyll accessing your @@ -428,6 +431,7 @@

USB Instruments:

+ Argyll drivers with existing OEM drivers:

If you currently have applications other than Argyll accessing your @@ -551,6 +555,7 @@

USB Instruments:

+ Argyll drivers with existing OEM drivers:

If you currently have applications other than Argyll accessing your diff --git a/doc/instruments.html b/doc/instruments.html index 016d5666..31748725 100644 --- a/doc/instruments.html +++ b/doc/instruments.html @@ -83,6 +83,7 @@

Operation of particular instruments

+ @@ -115,6 +116,7 @@

Operation of particular instruments

+ @@ -211,6 +213,7 @@

Operation of particular instruments

+ @@ -309,6 +312,7 @@

Operation of particular instruments

+ @@ -395,6 +399,7 @@

Operation of particular instruments

+ @@ -481,6 +486,7 @@

Operation of particular instruments

+ @@ -569,6 +575,7 @@

Operation of particular instruments

+ @@ -655,6 +662,7 @@

Operation of particular instruments

+ @@ -741,6 +749,7 @@

Operation of particular instruments

+ @@ -827,6 +836,7 @@

Operation of particular instruments

+ @@ -913,6 +923,7 @@

Operation of particular instruments

+ @@ -944,6 +955,7 @@

Operation of particular instruments

+ @@ -959,35 +971,33 @@

Operation of particular instruments

    Eye-One Display 3                         - i1 DisplayPro, DisplayPro Plus and ColorMunki - Display
+ Display/i1Display Studio
                                                -           [ The OEM - i1Display Pro, NEC SpectraSensor Pro,
-                   -                   -                   -        Quato Silver Haze 3 OEM,  HP - DreamColor, Wacom i1d3 and Toshiba TPA-1 are also reported to work.]
+           [ Other branded + i1d3's are also reported to work.]
    i1Pro2                                            + - spot and "swipe" reflective/emissive spectrometer.
    i1Pro3 and i1Pro3 Plus  +                + - spot and "swipe" reflective/emissive spectrometer.

@@ -1097,6 +1107,7 @@

Operation of particular instruments

+ @@ -1184,6 +1195,7 @@

Operation of particular instruments

+ @@ -1280,6 +1292,7 @@

Operation of particular instruments

+ @@ -1369,6 +1382,7 @@

Operation of particular instruments

+ @@ -1462,6 +1476,7 @@

Operation of particular instruments

+ @@ -1571,6 +1586,7 @@

Operation of particular instruments

+ @@ -1649,6 +1665,7 @@

Operation of particular instruments

+ @@ -2012,6 +2029,7 @@

Display Type
+ @@ -2202,6 +2220,7 @@

Refresh Rate Measurement

+ @@ -2264,6 +2283,7 @@

Refresh Rate Measurement

+ @@ -2329,6 +2349,7 @@

Refresh Rate Measurement

+ @@ -2380,6 +2401,7 @@

Refresh Rate Measurement

+ @@ -2475,6 +2497,7 @@

Refresh Rate Measurement

+ @@ -2800,6 +2823,7 @@

Refresh Rate Measurement

+ @@ -2906,6 +2930,7 @@

Refresh Rate Measurement

+ @@ -2993,6 +3018,7 @@

Refresh Rate Measurement

+ @@ -3096,6 +3122,7 @@

Refresh Rate Measurement

+ @@ -3152,6 +3179,7 @@

Refresh Rate Measurement

The i1Pro3 (standard + aperture) and i1Pro3 Plus (large aperture, polarizing filter) from  X-Rite are @@ -3187,6 +3215,7 @@

Refresh Rate Measurement

+ @@ -3195,6 +3224,7 @@

Refresh Rate Measurement

href="https://www.xrite.com/categories/calibration-profiling/i1basic-pro-3-plus">i1 + Basic Pro3 Plus.

@@ -3253,6 +3283,7 @@

Refresh Rate Measurement

+ @@ -3306,6 +3337,7 @@

Refresh Rate Measurement

+ @@ -3343,6 +3375,7 @@

Refresh Rate Measurement

+ @@ -3609,6 +3642,7 @@

Refresh Rate Measurement

+ @@ -3683,6 +3717,7 @@

Refresh Rate Measurement

+ @@ -3774,6 +3809,7 @@

Refresh Rate Measurement

+ @@ -3861,6 +3897,7 @@

Refresh Rate Measurement

+ @@ -3970,6 +4007,7 @@

Refresh Rate Measurement

+ @@ -3993,6 +4031,7 @@

Refresh Rate Measurement

+ Color Manager instruments are also reported to work. They will appear as a be a the same as the i1Display Pro. There are @@ -4099,6 +4138,7 @@

Refresh Rate Measurement

+ @@ -4191,6 +4231,7 @@

Refresh Rate Measurement

+ @@ -4278,6 +4319,7 @@

Refresh Rate Measurement

+ @@ -4390,6 +4432,7 @@

Refresh Rate Measurement

+ @@ -4477,6 +4520,7 @@

Refresh Rate Measurement

+ @@ -4598,6 +4642,7 @@

Refresh Rate Measurement

+ @@ -4685,6 +4730,7 @@

Refresh Rate Measurement

+ @@ -4898,6 +4944,7 @@

Refresh Rate Measurement

+ @@ -4994,6 +5041,7 @@

Refresh Rate Measurement

+ @@ -5085,6 +5133,7 @@

Refresh Rate Measurement

+ @@ -5246,6 +5295,7 @@

Refresh Rate Measurement

+ @@ -5342,6 +5392,7 @@

Refresh Rate Measurement

+ @@ -5433,6 +5484,7 @@

Refresh Rate Measurement

+ @@ -5471,6 +5523,7 @@

Refresh Rate Measurement

+ Elite appear to be identical hardware with different software from the manufacturer.
@@ -5507,6 +5560,7 @@

Refresh Rate Measurement

+ General [Default,CB1]                 @@ -5526,6 +5580,7 @@

Refresh Rate Measurement

+ - i.e. LCD with CCFL backlight
   e              @@ -5545,6 +5600,7 @@

Refresh Rate Measurement

+ Standard LED                               @@ -5564,6 +5620,7 @@

Refresh Rate Measurement

+ - i.e. LCD with white LED backlight
   b             @@ -5583,6 +5640,7 @@

Refresh Rate Measurement

+ Wide Gamut LED                         @@ -5602,6 +5660,7 @@

Refresh Rate Measurement

+ - i.e. LCD with RGB LED backlight
   i              @@ -5621,6 +5680,7 @@

Refresh Rate Measurement

+ GB LED                                        @@ -5640,6 +5700,7 @@

Refresh Rate Measurement

+ - i.e. LCD with GB-R Phosphor LED backlight

@@ -5739,6 +5800,7 @@

Refresh Rate Measurement

+ @@ -5844,6 +5906,7 @@

Refresh Rate Measurement

+ @@ -5931,6 +5994,7 @@

Refresh Rate Measurement

+ @@ -6018,6 +6082,7 @@

Refresh Rate Measurement

+ @@ -6075,6 +6140,7 @@

Refresh Rate Measurement

+ @@ -6132,6 +6198,7 @@

Refresh Rate Measurement

+ @@ -6188,6 +6255,7 @@

Refresh Rate Measurement

+ @@ -6245,6 +6313,7 @@

Refresh Rate Measurement

+ @@ -6302,6 +6371,7 @@

Refresh Rate Measurement

+ @@ -6346,6 +6416,7 @@

Refresh Rate Measurement

+ @@ -6408,6 +6479,7 @@

Refresh Rate Measurement

+ @@ -6465,6 +6537,7 @@

Refresh Rate Measurement

+ @@ -6511,6 +6584,7 @@

Refresh Rate Measurement

+ diff --git a/doc/scanin.html b/doc/scanin.html index 96d3cc21..aeae43a1 100644 --- a/doc/scanin.html +++ b/doc/scanin.html @@ -60,6 +60,8 @@

Usage Summary
Generate + + a chart reference (.cht) file
 Usage Summary
Output + + patch values in .val file
 
Usage Summary
Use + + image to measure color to convert printer pbase .ti2 to .ti3
@@ -85,12 +91,16 @@

Usage Summary
Same + + as -c, but accumulates more values to pbase .ti3
                      from + + subsequent pages
 
-rUsage Summary
Replace + + device values in pbase .ti3

                      Default + + is to create a scanner .ti3 file
 -F @@ -113,11 +127,15 @@

Usage Summary
Don't + + auto recognize, locate using four fiducual marks
 
-p                   Compensate + + for perspective distortion
 Usage Summary
Recognize + + chart in normal orientation only
                      Default + + is to recognize all possible chart angles
 
-m                   Return + + true mean (default is robust mean)
 -G gamma @@ -150,6 +174,8 @@

Usage Summary
Verbosity + + level 0-9
 -dUsage Summary
diag + + - B&W of input image

     Usage Summary
diag + + - Horizontal edge detection
    
Usage Summary
diag + + - Vertical edge detection
    
Usage Summary
diag + + - Groups detected
    
lUsage Summary
diag + + - Lines detected

     LUsage Summary
diag + + - All lines detected
     + + I                 diag + + - lines used to improve fit
     + + c                 diag + + - lines perspective corrected
Usage Summary
diag + + - lines rotated

     sUsage Summary
diag + + - sample boxes rotated

     oUsage Summary
diag + + - sample box outlines

     nUsage Summary
diag + + - sample box names

     aUsage Summary
diag + + - sample box areas

     pUsage Summary
diag + + - pixel areas sampled

  -O outputfile       Override the default output filename & extension.
-

Usage Details and Discussion

+

Usage Details and Discussion

scanin is setup to deal with a raster file that has been roughly cropped to a size that contains the test chart. It's exact orientation is not important [ie. there @@ -274,19 +332,21 @@

Usage Details and Discussion

reference files are normally set up with the assumption that the edges of the chart are visible within the image, and if the image is cropped to exclude the chart edges, it may well not recognize the - chart properly. It is designed to cope with a variety of - resolutions, and will cope with some degree of noise in the scan - (due to screening artefacts on the original, or film grain), but it - isn't really designed to accept very high resolution input. For - anything over 1200 pixels on a side, you should consider down - sampling the scan using a filtering down-sample, before submitting - the file to scanin. Similarly, any file with a large level of noise - (due to screening or scanner artefacts, or a noisy surrounding - texture) should consider cropping out the noisy surrounding, or down - sampling the image or filtering it with some average preserving - filter before submitting it to scanin. Examining the diagnostic - output (ie. -dig and -dil) may help in determining whether noise is - an issue.
+ chart properly. It is often better to crop out anything outside the + chart itself (i.e. labeling text, logo's below the chart etc.) It is + designed to cope with a variety of resolutions, and will cope with + some degree of noise in the scan (due to screening artefacts on the + original, or film grain), but it isn't really designed to accept + very high resolution input. For anything over 1200 pixels on a side, + you should consider down sampling the scan using a filtering + down-sample, before submitting the file to scanin. Similarly, any + file with a large level of noise (due to screening or scanner + artefacts, or a noisy surrounding texture) should consider cropping + out the noisy surrounding, or down sampling the image or filtering + it with some average preserving filter before submitting it to + scanin. Examining the diagnostic output (ie. -dig and -dil) may help + in determining whether noise is an issue. To check that the chart + has been correctly recognized, use -dipn and examine the diag image.

There are 5 basic modes that scanin operates in.
    @@ -340,6 +400,8 @@

    Usage Details and Discussion

    are: The TIFF file that is to be processed containing the image of a print test chart, the + + image recognition template file for the test chart generated by the printtarg tool, the input device ICC or MPP profile, Usage Details and Discussion

test chart printer device values and their patch identifiers and the base name for the resulting .ti3 file, and + + finally an optional name for the image recognition diagnostic output. The resulting .ti3 file will have the same base name as the input TIFF file. If there is more than one page in the test diff --git a/doc/spotread.html b/doc/spotread.html index 86f1a8ab..3877fa5e 100644 --- a/doc/spotread.html +++ b/doc/spotread.html @@ -68,6 +68,9 @@

Usage Summary

+ + + @@ -126,6 +129,9 @@

Usage Summary

+ + + @@ -189,6 +195,9 @@

Usage Summary

+ + + @@ -246,6 +255,9 @@

Usage Summary

+ + + @@ -303,6 +315,9 @@

Usage Summary

+ + + @@ -359,6 +374,9 @@

Usage Summary

+ + + @@ -398,6 +416,9 @@

Usage Summary

+ + + @@ -454,6 +475,9 @@

Usage Summary

+ + + @@ -510,6 +534,9 @@

Usage Summary

+ + + @@ -568,6 +595,9 @@

Usage Summary

+ + + @@ -627,6 +657,9 @@

Usage Summary

+ + + @@ -680,6 +713,9 @@

Usage Summary

+ + + @@ -691,6 +727,9 @@

Usage Summary

+ + + Use reflection white point relative chromatically adjusted mode
 -y X @@ -742,6 +781,9 @@

Usage Summary

+ + + @@ -795,6 +837,9 @@

Usage Summary

+ + + @@ -865,6 +910,9 @@

Usage Summary

+ + + @@ -925,6 +973,9 @@

Usage Summary

+ + + @@ -946,6 +997,9 @@

Usage Summary

+ + + 1955_2, shaw, J&V 1978_2
or file.cmf
@@ -997,6 +1051,9 @@

Usage Summary

+ + + @@ -1051,6 +1108,9 @@

Usage Summary

+ + + @@ -1105,6 +1165,9 @@

Usage Summary

+ + + @@ -1159,6 +1222,9 @@

Usage Summary

+ + + @@ -1213,6 +1279,9 @@

Usage Summary

+ + + @@ -1240,6 +1309,9 @@

Usage Summary

+ + + @@ -1256,6 +1328,9 @@

Usage Summary

+ + + Use -i param. illuminant for comuting L*a*b*
 -x @@ -1307,6 +1382,9 @@

Usage Summary

+ + + @@ -1362,6 +1440,9 @@

Usage Summary

+ + + @@ -1418,6 +1499,9 @@

Usage Summary

+ + + @@ -1473,6 +1557,9 @@

Usage Summary

+ + + @@ -1528,6 +1615,9 @@

Usage Summary

+ + + @@ -1541,6 +1631,9 @@

Usage Summary

+ + + Display density values

 -N                    @@ -1591,6 +1684,9 @@

Usage Summary

+ + + @@ -1627,6 +1723,9 @@

Usage Summary

+ + + @@ -1681,6 +1780,9 @@

Usage Summary

+ + + @@ -1740,6 +1842,9 @@

Usage Summary

+ + + @@ -1788,6 +1893,9 @@

Usage Summary

+ + + @@ -1826,6 +1934,9 @@

Usage Summary

+ + + @@ -1844,30 +1955,20 @@

Usage Summary

style="font-family: monospace;">                  Use averaging measurement mode (if - available).

-  -Y W:fname.sp         - - - - - - - - - - - - - - - - - - - - - - + available).
+
 -Y y +              +     Show even serial instrument + display calibration types in usage (slow!)
+
 -Y + W:fname.sp         Save white tile ref. spectrum to file
 -Y L                  Test for i1Pro Lamp @@ -1929,6 +2030,9 @@

Usage Summary

+ + + @@ -1988,6 +2092,9 @@

Usage Summary

+ + + @@ -2018,10 +2125,10 @@

Usage Details and Discussion

The Graph plots light wavelength on the X axis, and either absolute or relative level on the Y axis.

- +
- +
  Measurement Mode  
@@ -2071,6 +2178,9 @@

Usage Details and Discussion

+ + + @@ -2184,6 +2294,9 @@

Usage Details and Discussion

+ + + If the instrument does not support ambient mode, emissive mode will be used instead. An adaptive integration time will be used in @@ -2251,6 +2364,9 @@

Usage Details and Discussion

+ + + intending to use standard M0, M1 or M2 conditions, then use just the -I option and not the  -i option. See colprof -f for a fuller @@ -2461,6 +2577,9 @@

Usage Details and Discussion

+ + + @@ -2491,6 +2610,16 @@

Usage Details and Discussion

option uses an instruments averaging mode, if available (i.e. JETI 1211). Averaging mode maygive slower but more accurate measurements.

+ The -Y y + option will figure out all instrument types and show their specific + display calibrations in the usage display, even for serial connected + instruments. This may be very slow, as each serial port has to be + tried multiple times to figure out if an instrument is attached. + Normally only USB and similar quickly identified instruments will + have their specific calibration types listed in the -y + option usage. Note that you should set this on the command + line before triggering the usage, i.e. "spotread -Yy -?".
+
The -Y W:fname.sp option allows saving an instruments reference white tile reflectance spectrum to a file. Reflective instruments use a white reference tile to calibrate diff --git a/gamut/gammap.txt b/gamut/gammap.txt index f751248c..e2034505 100644 --- a/gamut/gammap.txt +++ b/gamut/gammap.txt @@ -121,13 +121,13 @@ Discussion of the gamut mapping algorithm used in Argyll: may not be the case though. If we assume that people do not in general adapt to the black points of a colorspace, then a consequence is that it is difficult to fully exploit - the full dynamic range of the colorspace, since an + the full dynamic range of the colorspace, since a source black that is misaligned with the destination black will probably not be able to achieve as low a J value, and this can noticably affect the percieved quality of an image. - The compromise deemed the best in Argyll, is to + The compromise I deemed the best in Argyll, is to assume that people do not adapt to black points, and that therefore only the white points should be aligned by rotating the source space around 0,0,0 @@ -231,7 +231,7 @@ Limitations and future challenges: The gammapweights structure would be expanded to add a weight as to how much the source hue cusps would be distorted. - [Done by Feb '06] + [Added to the code by Feb '06] 2) There is not much flexibility in what the gammapweights diff --git a/gamut/gamut.c b/gamut/gamut.c index 2544db9e..2cef990d 100644 --- a/gamut/gamut.c +++ b/gamut/gamut.c @@ -848,7 +848,7 @@ gvert *v2 /* Existing vertex */ /* Expand the gamut by adding a point. */ /* If nofilter is set, return NULL if the point */ /* is discarded, or the address of the point representing */ -/* the point added. If nofiler is not set, return NULL */ +/* the point added. If nofilter is not set, return NULL */ static gvert *expand_gamut( gamut *s, double pp[3] /* rectangular coordinate of point */ diff --git a/gamut/viewgam.c b/gamut/viewgam.c index 9a7a2f55..b59470db 100644 --- a/gamut/viewgam.c +++ b/gamut/viewgam.c @@ -62,7 +62,8 @@ void usage(char *diag, ...) { fprintf(stderr," -w Show as a wireframe\n"); fprintf(stderr," -s Show as a solid surace\n"); fprintf(stderr," infile.gam Name of .gam file\n"); - fprintf(stderr," Repeat above for each input file\n\n"); + fprintf(stderr," Repeat above for each input file\n"); + fprintf(stderr," Default is colored solid, then white, red etc. wireframes.\n\n"); fprintf(stderr," -n Don't add Lab axes\n"); fprintf(stderr," -k Add markers for prim. & sec. \"cusp\" points\n"); fprintf(stderr," -i Compute and print intersecting volume of first 2 gamuts\n"); diff --git a/h/aconfig.h b/h/aconfig.h index a3a420dd..810461d1 100644 --- a/h/aconfig.h +++ b/h/aconfig.h @@ -24,8 +24,8 @@ /* major number = 8 bits */ #ifndef USE_NG_VERSION -# define ARGYLL_VERSION 0x02021 -# define ARGYLL_VERSION_STR "2.2.1" +# define ARGYLL_VERSION 0x02030 +# define ARGYLL_VERSION_STR "2.3.0" #else # define ARGYLL_VERSION NG_VERSION # define ARGYLL_VERSION_STR "NG_VERSION_STR" diff --git a/log.txt b/log.txt index 472a3dc7..b16ae42d 100644 --- a/log.txt +++ b/log.txt @@ -8,6 +8,41 @@ Not included yet: * Started adding comms for Lumagen Radiance detection. +Version 2.3.0 24th December 2021 +------------- + +* Fixed spotread -YL (i1Pro1/2 lamp remediation) to function even + if calibration is impossible due to the white reference being + out of tolerance. + +* Fix SpyderX faulty initial black calibration (it was asking for + calibration every measurement). + +* Added icomuf_reset_before_close flag for SpyderX, as some versions + of the instrument have been reported to lock up after use. + +* Modified the ArgyllCMS CIECAM02 implementation to include a + blue hue linearization tweak, to improve the "blue goes purple" + effect when gamut mapping or clipping highly saturated blues + to smaller gamuts. + +* Added spotread -Y y option that forces the listing of + instrument specific display calibrations in the usage, + even for serial instruments. + +* Removed native i1d3 C6 instrument support as a favor to X-Rite. + Anybody adversely affected should contact me (Graeme Gill). + +* Modified usbio_lx.c cancel_req() to supress cancel_req: failed error + message, since this seems benign. + +* Improved cxf2ti3 so that it should cope with XML that uses "Colour" + spelling rather than "Color". + +* Added I1D3_ESCAPE environment variable to allow a user to + potentialy use any current or future OEM coded i1d3 instrument. + + Version 2.2.1 17th September 2021 ------------- @@ -91,7 +126,7 @@ Version 2.1.2 14th January 2020 conversion and the i1Pro2 one. * Changed targen round down/up to 0%/100% to have a tighter - tollerance of 0.5% rather than 2%, so that -n values of + tolerance of 0.5% rather than 2%, so that -n values of L* 1 and 99 are not rounded. * Fix bug in xicclu -v2 option when operating on a .cal file. @@ -347,7 +382,7 @@ Version 2.0.0 17th November 2017 CCT delta E in 1960 Duv units and others in Delta E 2000. Also renamed (Invalid) notification to (Caution), since the computed values themselves are not necessarily invalid, - just that the illuminant is out of whiteness (red/green) tollerance. + just that the illuminant is out of whiteness (red/green) tolerance. * Added ARGYLL_UNTWIST_GAMUT_SURFACE environment variable, that enables extra gamut clip surface processing that @@ -2660,7 +2695,7 @@ Version 1.1.0 RC1 (6 November 2009) The second issue was in not being sufficiently sensitive to sensor saturation for display measurement. Fix by - now having a zero tollerance, and allowing for 3 different + now having a zero tolerance, and allowing for 3 different display measurement exposures. * Fix bug in link/collink -ke where the K value was being diff --git a/numlib/numsup.h b/numlib/numsup.h index 6f5c61d3..13f349d6 100644 --- a/numlib/numsup.h +++ b/numlib/numsup.h @@ -114,7 +114,7 @@ #define PNTR UINT_PTR #define PF64PREC "I64" /* printf format precision specifier */ -#define CF64PREC "LL" /* Constant precision specifier */ +#define CF64PREC "i64" /* Constant precision specifier */ #ifndef ATTRIBUTE_NORETURN # define ATTRIBUTE_NORETURN __declspec(noreturn) diff --git a/plot/plot.h b/plot/plot.h index 885937b9..4a1715c9 100644 --- a/plot/plot.h +++ b/plot/plot.h @@ -173,9 +173,9 @@ typedef struct { void init_g(plot_g *g); void add_vec_g(plot_g *g, double x1, double y1, double x2, double y2, float *rgb); void add_sym_g(plot_g *g, double x3, double y3, plot_sym st, float *rgb, char *ptext); -int get_xy_g(plot_g *g, double xy[2], int ix); -int set_xy_g(plot_g *g, double xy[2], int ix); -int get_vxyix_g(plot_g *g); +int get_xy_g(plot_g *g, double xy[2], int ix); /* Fetch point at index */ +int set_xy_g(plot_g *g, double xy[2], int ix); /* Change point at index */ +int get_vxyix_g(plot_g *g); /* Get the current index number */ void do_plot_g(plot_g *g, double xmin, double xmax, double ymin, double ymax, double ratio, int zero, int dowait); diff --git a/profile/cxf2ti3.c b/profile/cxf2ti3.c index e98be5d9..9c8ed1d4 100644 --- a/profile/cxf2ti3.c +++ b/profile/cxf2ti3.c @@ -104,13 +104,16 @@ type_cb(mxml_node_t *node) { // // 0.0580 0.0594 0.0594 0.0584 0.0581 0.0591 0.0599 0.0601 0.0603 0.0610 0.0634 0.0695 0.0760 0.0786 0.0798 0.0826 0.0897 0.1024 0.1197 0.1350 0.1434 0.1455 0.1499 0.1594 0.1721 0.1842 0.1913 0.1928 0.1878 0.1734 0.1704 - if (pfxcmp(pname, "ColorValues") == 0 + if (( pfxcmp(pname, "ColorValues") == 0 + || pfxcmp(pname, "ColourValues") == 0) && pfxcmp(name, "ReflectanceSpectrum") == 0) return MXML_REAL; // return MXML_OPAQUE; if ((pfxcmp(pname, "ColorCIELab") == 0 - || pfxcmp(pname, "ColorSpaceCIELab") == 0) + || pfxcmp(pname, "ColorSpaceCIELab") == 0 + || pfxcmp(pname, "ColourCIELab") == 0 + || pfxcmp(pname, "ColourSpaceCIELab") == 0) && (pfxcmp(name, "L") == 0 || pfxcmp(name, "A") == 0 || pfxcmp(name, "B") == 0)) @@ -118,21 +121,28 @@ type_cb(mxml_node_t *node) { if ((pfxcmp(pname, "ColorCIEXYZ") == 0 || pfxcmp(pname, "ColorIEXYZ") == 0 - || pfxcmp(pname, "ColorSpaceCIEXYZ") == 0) + || pfxcmp(pname, "ColorSpaceCIEXYZ") == 0 + || pfxcmp(pname, "ColourCIEXYZ") == 0 + || pfxcmp(pname, "ColourIEXYZ") == 0 + || pfxcmp(pname, "ColourSpaceCIEXYZ") == 0) && (pfxcmp(name, "X") == 0 || pfxcmp(name, "Y") == 0 || pfxcmp(name, "Z") == 0)) return MXML_REAL; if ((pfxcmp(pname, "ColorSRGB") == 0 - || pfxcmp(pname, "ColorSpaceSRGB") == 0) + || pfxcmp(pname, "ColorSpaceSRGB") == 0 + || pfxcmp(pname, "ColourSRGB") == 0 + || pfxcmp(pname, "ColourSpaceSRGB") == 0) && (pfxcmp(name, "R") == 0 || pfxcmp(name, "G") == 0 || pfxcmp(name, "B") == 0)) return MXML_REAL; if ((pfxcmp(pname, "ColorCMYK") == 0 - || pfxcmp(pname, "ColorSpaceCMYK") == 0) + || pfxcmp(pname, "ColorSpaceCMYK") == 0 + || pfxcmp(pname, "ColourCMYK") == 0 + || pfxcmp(pname, "ColourSpaceCMYK") == 0) && (pfxcmp(name, "Cyan") == 0 || pfxcmp(name, "Magenta") == 0 || pfxcmp(name, "Yellow") == 0 @@ -148,7 +158,8 @@ type_cb(mxml_node_t *node) { if ((pfxcmp(pname, "IlluminationOptions") == 0 || pfxcmp(pname, "TristimulusSpec") == 0 - || pfxcmp(pname, "ColorSpaceSpecificationSpectrumTristimulus") == 0) + || pfxcmp(pname, "ColorSpaceSpecificationSpectrumTristimulus") == 0 + || pfxcmp(pname, "ColourSpaceSpecificationSpectrumTristimulus") == 0) && (pfxcmp(name, "Illuminant") == 0 || pfxcmp(name, "Observer") == 0 || pfxcmp(name, "FieldOfView") == 0)) @@ -555,13 +566,15 @@ main(int argc, char *argv[]) { /* Known values are: Standard, Color */ /* May be Trial, Target, Substrate, Colorant, ... ? */ if (strcmp(attr, "Standard") != 0 - && strcmp(attr, "Color") != 0) { + && strcmp(attr, "Color") != 0 + && strcmp(attr, "Colour") != 0) { a1logd(g_log, 6, "cxf2ti3: skipping node with ObjectType = '%s'\n",attr); goto next; /* Skip this one */ } #endif - if ((ppvals = mxmlFindElement(node, node, pfx(&ctx,"ColorValues"), NULL, NULL, MXML_DESCEND_FIRST)) == NULL) { + if ((ppvals = mxmlFindElement(node, node, pfx(&ctx,"ColorValues"), NULL, NULL, MXML_DESCEND_FIRST)) == NULL + && (ppvals = mxmlFindElement(node, node, pfx(&ctx,"ColourValues"), NULL, NULL, MXML_DESCEND_FIRST)) == NULL) { a1logd(g_log, 4, "cxf2ti3: no reference ColorValues element - skipping\n"); goto next; } @@ -600,7 +613,9 @@ main(int argc, char *argv[]) { /* See if there is ColorCIELab */ if ((pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorCIELab"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL - || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorSpaceCIELab"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorSpaceCIELab"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourCIELab"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourSpaceCIELab"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { char *key[3] = { "L", "A", "B" }; a1logd(g_log, 4, "cxf2ti3: got ColorCIELab\n"); @@ -608,7 +623,10 @@ main(int argc, char *argv[]) { /* Check which color specification is being used with Lab */ if (LabSpecification == NULL) { LabSpecification = mxmlElementGetAttr(pvals, "ColorSpecification"); - a1logd(g_log, 4, "cxf2ti3: got LabSpecification '%s'\n",LabSpecification); + if (LabSpecification == NULL) + LabSpecification = mxmlElementGetAttr(pvals, "ColourSpecification"); + if (LabSpecification != NULL) + a1logd(g_log, 4, "cxf2ti3: got LabSpecification '%s'\n",LabSpecification); } for (j = 0; j < 3; j++) { @@ -639,7 +657,10 @@ main(int argc, char *argv[]) { /* See if there is ColorCIEXYZ */ if ((pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorCIEXYZ"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorIEXYZ"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL - || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorSpaceCIEXYZ"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorSpaceCIEXYZ"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourCIEXYZ"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourIEXYZ"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourSpaceCIEXYZ"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { char *key[3] = { "X", "Y", "Z" }; a1logd(g_log, 4, "cxf2ti3: got ColorCIEXYZ\n"); @@ -647,7 +668,10 @@ main(int argc, char *argv[]) { /* Check which color specification is being used with XYZ */ if (XYZSpecification == NULL) { XYZSpecification = mxmlElementGetAttr(pvals, "ColorSpecification"); - a1logd(g_log, 4, "cxf2ti3: got XYZSpecification '%s'\n",XYZSpecification); + if (XYZSpecification == NULL) + XYZSpecification = mxmlElementGetAttr(pvals, "ColourSpecification"); + if (XYZSpecification != NULL) + a1logd(g_log, 4, "cxf2ti3: got XYZSpecification '%s'\n",XYZSpecification); } for (j = 0; j < 3; j++) { @@ -684,7 +708,10 @@ main(int argc, char *argv[]) { /* Check which color specification is being used with XYZ */ if (SpectSpecification == NULL) { SpectSpecification = mxmlElementGetAttr(pvals, "ColorSpecification"); - a1logd(g_log, 4, "cxf2ti3: got SpectSpecification '%s'\n",SpectSpecification); + if (SpectSpecification == NULL) + SpectSpecification = mxmlElementGetAttr(pvals, "ColourSpecification"); + if (SpectSpecification != NULL) + a1logd(g_log, 4, "cxf2ti3: got SpectSpecification '%s'\n",SpectSpecification); } if ((elem = mxmlElementGetAttr(pvals, "StartWL")) != NULL) { @@ -768,7 +795,8 @@ main(int argc, char *argv[]) { } /* Read any device color values */ - if ((ppvals = mxmlFindElement(node, node, pfx(&ctx,"DeviceColorValues"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { + if ((ppvals = mxmlFindElement(node, node, pfx(&ctx,"DeviceColorValues"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (ppvals = mxmlFindElement(node, node, pfx(&ctx,"DeviceColourValues"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { a1logd(g_log, 4, "cxf2ti3: got DeviceColorValues\n"); } @@ -779,7 +807,9 @@ main(int argc, char *argv[]) { /* See if there is ColorRGB */ if ((pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorRGB"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL - || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorSpaceRGB"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorSpaceRGB"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourRGB"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourSpaceRGB"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { char *key[3] = { "Red", "Green", "Blue" }; a1logd(g_log, 4, "cxf2ti3: got ColorRGB\n"); @@ -811,7 +841,9 @@ main(int argc, char *argv[]) { /* See if there is ColorCMYK */ if ((pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorCMYK"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL - || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorSpaceCMYK"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColorSpaceCMYK"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourCMYK"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL + || (pvals = mxmlFindElement(ppvals, ppvals, pfx(&ctx,"ColourSpaceCMYK"), NULL, NULL, MXML_DESCEND_FIRST)) != NULL) { char *key[4] = { "Cyan", "Magenta", "Yellow", "Black" }; a1logd(g_log, 4, "cxf2ti3: got ColorCMYK\n"); diff --git a/profile/profout.c b/profile/profout.c index 679f2ef0..8fdd25a6 100644 --- a/profile/profout.c +++ b/profile/profout.c @@ -61,7 +61,7 @@ for the device->PCS tables by calling xicc->set_luobj(). For a CLUT type profile, create a gamut mapping object and - setup all the other bits and peices needed to convert a color + setup all the other bits and pieces needed to convert a color from PCS to device, then use (icc) icmSetMultiLutTables() which will call back the out_b2a_input(), out_b2a_clut() and out_b2a_output() functions. diff --git a/scanin/scanrd.c b/scanin/scanrd.c index 775975ec..61b011c7 100644 --- a/scanin/scanrd.c +++ b/scanin/scanrd.c @@ -29,7 +29,9 @@ #define AA_LINES /* Plot diagnostics using anti-aliased lines */ #define MATCHCC 0.25 /* Match correlation threshold - reject any match under this */ - /* (Might want to be able to override this in command line) */ + /* (Might want to be able to override this in command line ?) */ + +#define WMATCHCCR 0.5 /* Worst match correlation min. threshold ratio to best */ #define ALT_ROT_TH 0.7 /* Correlation threshold of alternate rotations to be greater than this */ @@ -143,7 +145,6 @@ void *ddata /* Opaque data for write_line */ if (s->flags & SI_SHOW_LINES) { s->flags &= ~SI_SHOW_PERS; /* Calc perspective failed! */ s->flags &= ~SI_SHOW_ROT; /* Calc rotation not done! */ - show_lines(s); } goto sierr; /* Error */ } @@ -154,7 +155,6 @@ void *ddata /* Opaque data for write_line */ if (calc_rotation(s)) { if (s->flags & SI_SHOW_LINES) { s->flags &= ~SI_SHOW_ROT; /* Calc rotation failed! */ - show_lines(s); } goto sierr; /* Error */ } @@ -237,8 +237,9 @@ void *ddata /* Opaque data for write_line */ if (s->verb >= 2) DBG((dbgo,"About to compute match transform for rotation %f deg.\n", DEG(s->rots[s->crot].irot))); - if (compute_ptrans(s)) + if (compute_ptrans(s)) { goto sierr; + } /* Setup the input boxes ready for scanning in the input values */ if (s->verb >= 2) @@ -307,11 +308,11 @@ void *ddata /* Opaque data for write_line */ show_sbox(s); /* Draw sample box outlines on diagnostic raster */ } } +sierr:; if (s->flags & SI_SHOW_LINES) if(show_lines(s)) goto sierr; /* Error */ -sierr:; if (s->verb >= 2) DBG((dbgo,"About to write diag file\n")); if (scanrd_write_diag(s)) @@ -2619,6 +2620,8 @@ scanrd_ *s ) { ematch xx, yy, xy, yx, xix, yiy, xiy, yix; /* All 8 matches needed to detect rotations */ double r0, r90, r180, r270; /* Correlation for each extra rotation of target */ + double rr[4], bcc, wcc; + int i; /* Check out all the matches */ if (s->verb >= 2) DBG((dbgo,"Checking xx\n")); @@ -2669,15 +2672,34 @@ scanrd_ *s r270 = sqrt(xy.cc * xy.cc + yix.cc * yix.cc) * (xy.scale > yix.scale ? yix.scale/xy.scale : xy.scale/yix.scale); - if (s->verb >= 2) + rr[0] = r0; + rr[1] = r90; + rr[2] = r180; + rr[3] = r270; + + bcc = -1.0; + for (i = 0; i < 4; i++) { + if (rr[i] > bcc) + bcc = rr[i]; + } + wcc = bcc; + for (i = 0; i < 4; i++) { + if (rr[i] < wcc) + wcc = rr[i]; + } + + if (s->verb >= 2) { DBG((dbgo,"r0 = %f, r90 = %f, r180 = %f, r270 = %f\n",r0,r90,r180,r270)); + DBG((dbgo,"bcc = %f, wcc = %f\n",bcc, wcc)); + } s->norots = 0; if (s->flags & SI_GENERAL_ROT) { /* If general rotation allowed */ if (s->xpt == 0) { /* No expected color information to check rotations agaist */ /* so choose the single best rotation by the edge matching */ DBG((dbgo,"There is no expected color information, so best fit rotations will be used\n")); - if (r0 >= MATCHCC && r0 >= r90 && r0 >= r180 && r0 >= r270) { + if (r0 >= MATCHCC && r0 >= r90 && r0 >= r180 && r0 >= r270 + && wcc < (WMATCHCCR * bcc)) { s->rots[0].ixoff = -xx.off; s->rots[0].ixscale = 1.0/xx.scale; s->rots[0].iyoff = -yy.off; @@ -2685,7 +2707,8 @@ scanrd_ *s s->rots[0].irot = s->irot; s->rots[0].cc = r0; s->norots = 1; - } else if (r90 >= MATCHCC && r90 >= r180 && r90 >= r270) { + } else if (r90 >= MATCHCC && r90 >= r180 && r90 >= r270 + && wcc < (WMATCHCCR * bcc)) { s->rots[0].ixoff = -xiy.off; s->rots[0].ixscale = 1.0/xiy.scale; s->rots[0].iyoff = -yx.off; @@ -2693,7 +2716,8 @@ scanrd_ *s s->rots[0].irot = s->irot + M_PI_2; s->rots[0].cc = r90; s->norots = 1; - } else if (r180 >= MATCHCC && r180 >= r270) { + } else if (r180 >= MATCHCC && r180 >= r270 + && wcc < (WMATCHCCR * bcc)) { s->rots[0].ixoff = -xix.off; s->rots[0].ixscale = 1.0/xix.scale; s->rots[0].iyoff = -yiy.off; @@ -2701,7 +2725,8 @@ scanrd_ *s s->rots[0].irot = s->irot + M_PI; s->rots[0].cc = r180; s->norots = 1; - } else if (r270 >= MATCHCC) { /* 270 extra target rotation */ + } else if (r270 >= MATCHCC + && wcc < (WMATCHCCR * bcc)) { s->rots[0].ixoff = -xy.off; s->rots[0].ixscale = 1.0/xy.scale; s->rots[0].iyoff = -yix.off; @@ -2712,23 +2737,14 @@ scanrd_ *s } } else { /* Got expected color info, so try reasonable rotations */ - double bcc; /* Best correlation coeff */ - - if (r0 >= r90 && r0 >= r180 && r0 >= r270) - bcc = r0; - else if (r90 >= r180 && r90 >= r270) - bcc = r90; - else if (r180 >= r270) - bcc = r180; - else - bcc = r270; + double arcc; - bcc *= ALT_ROT_TH; /* Threshold for allowing alternate rotation */ - if (bcc < MATCHCC) - bcc = MATCHCC; + arcc = bcc * ALT_ROT_TH; /* Threshold for allowing alternate rotation */ + if (arcc < MATCHCC) + arcc = MATCHCC; s->norots = 0; - if (r0 >= bcc) { + if (r0 >= arcc && wcc < (WMATCHCCR * bcc)) { s->rots[s->norots].ixoff = -xx.off; s->rots[s->norots].ixscale = 1.0/xx.scale; s->rots[s->norots].iyoff = -yy.off; @@ -2737,7 +2753,7 @@ scanrd_ *s s->rots[s->norots].cc = r0; s->norots++; } - if (r90 >= bcc) { + if (r90 >= arcc && wcc < (WMATCHCCR * bcc)) { s->rots[s->norots].ixoff = -xiy.off; s->rots[s->norots].ixscale = 1.0/xiy.scale; s->rots[s->norots].iyoff = -yx.off; @@ -2746,7 +2762,7 @@ scanrd_ *s s->rots[s->norots].cc = r90; s->norots++; } - if (r180 >= bcc) { + if (r180 >= arcc && wcc < (WMATCHCCR * bcc)) { s->rots[s->norots].ixoff = -xix.off; s->rots[s->norots].ixscale = 1.0/xix.scale; s->rots[s->norots].iyoff = -yiy.off; @@ -2755,7 +2771,7 @@ scanrd_ *s s->rots[s->norots].cc = r180; s->norots++; } - if (r270 >= bcc) { + if (r270 >= arcc && wcc < (WMATCHCCR * bcc)) { s->rots[s->norots].ixoff = -xy.off; s->rots[s->norots].ixscale = 1.0/xy.scale; s->rots[s->norots].iyoff = -yix.off; diff --git a/spectro/Jamfile b/spectro/Jamfile index 53d2953e..68b4efca 100644 --- a/spectro/Jamfile +++ b/spectro/Jamfile @@ -248,6 +248,14 @@ if $(USE_CMFM) = true && [ GLOB [ NormPaths . ] : 1501_cal.c ] { Main 1501_cal : 1501_cal.c ; } +# Misc. test code +if [ GLOB [ NormPaths . ] : i1d3test.c ] { + Main i1d3test : i1d3test.c ; +} +if [ GLOB [ NormPaths . ] : i1d3test2.c ] { + Main i1d3test2 : i1d3test2.c ; +} + #display test window test/Lut loader utility # [ Could avoid need for libinst libusb etc. # by separating system dependent utils to a separate library .] @@ -306,7 +314,6 @@ MainVariant xdg_bds : xdg_bds.c : : STANDALONE_TEST : : : libconv ; #Main t8 : t8.c ; #Main t9 : t9.c ; #Main i1d3eval : i1d3eval.c ; -#Main i1d3_msrand.c : i1d3_msrand.c ; # Simple test code of aglob if [ GLOB [ NormPaths . ] : globtest.c ] { diff --git a/spectro/Jamfile.SA b/spectro/Jamfile.SA new file mode 100644 index 00000000..5b016222 --- /dev/null +++ b/spectro/Jamfile.SA @@ -0,0 +1,32 @@ + +# Jamfile for compiling standalone instrumement driver + +#ifndef NOT_GNU_COPYRIGHT +# Copyright 2000 - 2007 Graeme W. Gill +# This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :- +# see the License2.txt file for licencing details. +#else +# NG_COPYRIGHT_1 +# NG_COPYRIGHT_2 +# NG_COPYRIGHT_3 +#endif + +PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on +#PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags +#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags +PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags + +DEFINES += SALONEINSTLIB ENABLE_SERIAL ENABLE_FAST_SERIAL ENABLE_USB ; + +INSTOBJS = dtp20.c dtp22.c dtp41.c dtp51.c dtp92.c ss.c ss_imp.c i1disp.c i1d3.c i1pro.c i1pro_imp.c i1pro3.c i1pro3_imp.c munki.c munki_imp.c hcfr.c huey.c colorhug.c spyd2.c spydX.c specbos.c kleink10.c ex1.c smcube.c ; + +Library libinst : conv.c sa_conv.c aglob.c inst.c numsup.c rspl1.c icoms.c usbio.c hidio.c insttypes.c disptechs.c rspec.c xrga.c pollem.c xspect.c xdg_bds.c ccss.c ccmx.c pars.c cgats.c $(INSTOBJS) ; + +Library libinstappsup : instappsup.c ; + +LINKLIBS = libinst libinstappsup ; + +MainsFromSources spotread.c ; + +Main oeminst : oeminst.c oemarch.c inflate.c vinflate.c LzmaDec.c ; + diff --git a/spectro/Makefile.SA b/spectro/Makefile.SA index 5913126b..b183ab35 100644 --- a/spectro/Makefile.SA +++ b/spectro/Makefile.SA @@ -39,7 +39,8 @@ 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) ex1$(SUFOBJ) smcube$(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) i1pro3$(SUFOBJ) i1pro3_imp$(SUFOBJ) munki$(SUFOBJ) munki_imp$(SUFOBJ) hcfr$(SUFOBJ) huey$(SUFOBJ) colorhug$(SUFOBJ) spyd2$(SUFOBJ) spydX.$(SUFOBJ) specbos$(SUFOBJ) kleink10$(SUFOBJ) ex1$(SUFOBJ) smcube$(SUFOBJ) 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 diff --git a/spectro/afiles b/spectro/afiles index d10a57de..e8254ad8 100644 --- a/spectro/afiles +++ b/spectro/afiles @@ -138,6 +138,7 @@ SOtele.sp linear.cal strange.cal ccxx.ti1 +Jamfile.SA Makefile.SA Makefile.OSX Makefile.UNIX diff --git a/spectro/ccxxmake.c b/spectro/ccxxmake.c index 5fba1bc1..d7043f61 100644 --- a/spectro/ccxxmake.c +++ b/spectro/ccxxmake.c @@ -169,7 +169,7 @@ usage(int flag, char *diag, ...) { // fprintf(stderr," -d fake Use a fake (ICC profile) display device for testing, fake%s if present\n",ICC_FILE_EXT); fprintf(stderr," -p Use telephoto mode (ie. for a projector, if available)\n"); fprintf(stderr," -a Use ambient measurement mode (ie. for a projector, if available)\n"); - cap = inst_show_disptype_options(stderr, " -y c|l ", icmps, 1); + cap = inst_show_disptype_options(stderr, " -y c|l ", icmps, 1, 0); fprintf(stderr," -z disptype Different display type for spectrometer (see -y)\n"); fprintf(stderr," -P ho,vo,ss[,vs] Position test window and scale it\n"); fprintf(stderr," ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.\n"); diff --git a/spectro/chartread.c b/spectro/chartread.c index 96346aa8..61598f09 100644 --- a/spectro/chartread.c +++ b/spectro/chartread.c @@ -2156,7 +2156,7 @@ usage() { } fprintf(stderr," -t Use transmission measurement mode\n"); fprintf(stderr," -d Use display measurement mode (white Y relative results)\n"); - cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0); + cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0, 0); fprintf(stderr," -e Emissive for transparency on a light box\n"); fprintf(stderr," -p Measure patch by patch rather than strip\n"); fprintf(stderr," -x [lx] Take external values, either L*a*b* (-xl) or XYZ (-xx).\n"); diff --git a/spectro/colorhug.c b/spectro/colorhug.c index 8f0de51d..51debc70 100644 --- a/spectro/colorhug.c +++ b/spectro/colorhug.c @@ -518,6 +518,7 @@ colorhug_get_serialnumber (colorhug *p) return ev; p->ser_no = buf2uint_le(obuf + 0); + sprintf(p->serno, "%u", p->ser_no); a1logd(p->log,2,"colorhug: Serial number = %d\n",p->ser_no); @@ -669,6 +670,17 @@ colorhug_init_inst(inst *pp) return inst_ok; } +static char *colorhug_get_serial_no(inst *pp) { + colorhug *p = (colorhug *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serno; +} + /* Read a single sample */ static inst_code colorhug_read_sample( @@ -1221,6 +1233,7 @@ extern colorhug *new_colorhug(icoms *icom, instType dtype) { p->init_coms = colorhug_init_coms; p->init_inst = colorhug_init_inst; p->capabilities = colorhug_capabilities; + p->get_serial_no = colorhug_get_serial_no; p->check_mode = colorhug_check_mode; p->set_mode = colorhug_set_mode; p->get_disptypesel = colorhug_get_disptypesel; diff --git a/spectro/colorhug.h b/spectro/colorhug.h index 3bddf761..54835a96 100644 --- a/spectro/colorhug.h +++ b/spectro/colorhug.h @@ -80,6 +80,7 @@ struct _colorhug { colorhug_model stype; /* Instrument sub-model */ int maj, min, uro; /* Version number */ int ser_no; /* Serial number */ + char serno[20]; /* Serial number as string */ inst_disptypesel *dtlist; /* Display Type list */ int ndtlist; /* Number of valid dtlist entries */ diff --git a/spectro/conv.c b/spectro/conv.c index 5652f7f3..82e1ed3a 100644 --- a/spectro/conv.c +++ b/spectro/conv.c @@ -108,121 +108,66 @@ #ifdef NT /* wait for and then return the next character from the keyboard */ -/* (If not_interactive, return getchar()) */ +/* (If not_interactive set, wait for next stdin character but discard cr or lf) */ int next_con_char(void) { int c; if (not_interactive) { HANDLE stdinh; - char buf[1]; + char buf[10], rv = 0; DWORD bread; if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { return 0; } - /* Ignore end of line characters */ + /* Try and read any end of line characters */ for (;;) { - if (ReadFile(stdinh, buf, 1, &bread, NULL) - && bread == 1 - && buf[0] != '\r' && buf[0] != '\n') { - return buf[0]; + buf[0] = 0; + if (ReadFile(stdinh, buf, 3, &bread, NULL) + && bread >= 1) { + rv = buf[0]; + break; } } + + return rv; } c = _getch(); 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 - */ -/* trying to do this manually typically doesn't work unless you are */ -/* very fast and lucky. */ -static int th_read_char(void *pp) { - char *rp = (char *)pp; - HANDLE stdinh; - char buf[1]; - 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') { - *rp = buf[0]; - } - - return 0; -} -#endif /* NEVER */ - /* If there is one, return the next character from the keyboard, else return 0 */ -/* (If not_interactive, always returns 0) */ +/* (If not_interactive set, return next stdin character if available, but discard cr or lf) */ 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; - 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 in theory fix this, but it's not available in WinXP, only Vista+, */ - /* 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; - } - - /* 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; + char buf[10] = { 0 }; DWORD bread; + int rv = 0; if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { - return 0; + 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; + for (;;) { + if (WaitForSingleObject(stdinh, 0) == WAIT_OBJECT_0) { + buf[0] = buf[1] = buf[2] = 0; + if (ReadFile(stdinh, buf, 3, &bread, NULL)) { +// fprintf(stderr,"Read %d chars 0x%x 0x%x 0x%x\n",bread,buf[0],buf[1], buf[2]); + rv = buf[0]; + break; + } } + rv = 0; + break; } -#endif /* !NEVER */ - return 0; + + return rv; } /* Assume it's the console */ @@ -234,7 +179,7 @@ int poll_con_char(void) { } /* Suck all characters from the keyboard */ -/* (If not_interactive, does nothing ?) */ +/* (If not_interactive set, discard all pending characters of stdin) */ void empty_con_chars(void) { if (not_interactive) { @@ -619,14 +564,14 @@ int system_processors() { #if defined(UNIX) /* Wait for and return the next character from the keyboard */ -/* (If not_interactive, return getchar()) */ +/* (If not_interactive set, wait for next stdin character but discard cr or lf) */ int next_con_char(void) { struct pollfd pa[1]; /* Poll array to monitor stdin */ struct termios origs, news; char rv = 0; + /* Configure stdin to be ready with just one character if interactive */ if (!not_interactive) { - /* Configure stdin to be ready with just one character */ if (tcgetattr(STDIN_FILENO, &origs) < 0) a1logw(g_log, "next_con_char: tcgetattr failed with '%s' on stdin", strerror(errno)); news = origs; @@ -637,25 +582,24 @@ int next_con_char(void) { a1logw(g_log, "next_con_char: tcsetattr failed with '%s' on stdin", strerror(errno)); } - /* Wait for stdin to have a character */ + /* Wait for stdin to have at least one character. */ + /* If not_interactive set then it may be a character followed by cr and/or lf to flush it */ pa[0].fd = STDIN_FILENO; pa[0].events = POLLIN | POLLPRI; pa[0].revents = 0; - if (poll_x(pa, 1, -1) > 0 + if (poll_x(pa, 1, -1) > 0 /* wait until there is something */ && (pa[0].revents == POLLIN - || pa[0].revents == POLLPRI)) { - char tb[3]; - if (read(STDIN_FILENO, tb, 1) > 0) { /* User hit a key */ - rv = tb[0] ; + || pa[0].revents == POLLPRI)) { /* Something there */ + char tb[10]; + if (read(STDIN_FILENO, tb, 3) > 0) { /* get it and any return */ + rv = tb[0]; } } else { - if (!not_interactive) - tcsetattr(STDIN_FILENO, TCSANOW, &origs); a1logw(g_log, "next_con_char: poll on stdin returned unexpected value 0x%x",pa[0].revents); } - /* Restore stdin */ + /* Restore stdin if interactive */ if (!not_interactive && tcsetattr(STDIN_FILENO, TCSANOW, &origs) < 0) { a1logw(g_log, "next_con_char: tcsetattr failed with '%s' on stdin", strerror(errno)); } @@ -664,14 +608,14 @@ int next_con_char(void) { } /* If here is one, return the next character from the keyboard, else return 0 */ -/* (If not_interactive, always returns 0) */ +/* (If not_interactive set, return next stdin character if available, but discard cr or lf) */ int poll_con_char(void) { struct pollfd pa[1]; /* Poll array to monitor stdin */ struct termios origs, news; char rv = 0; + /* Configure stdin to be ready with just one character if interactive */ if (!not_interactive) { - /* Configure stdin to be ready with just one character */ if (tcgetattr(STDIN_FILENO, &origs) < 0) a1logw(g_log, "poll_con_char: tcgetattr failed with '%s' on stdin", strerror(errno)); news = origs; @@ -682,33 +626,30 @@ int poll_con_char(void) { a1logw(g_log, "poll_con_char: tcsetattr failed with '%s' on stdin", strerror(errno)); } - /* Wait for stdin to have a character */ + /* See if stdin has a character */ + /* If not_interactive set then it may be a character followed by cr and/or lf to flush it */ pa[0].fd = STDIN_FILENO; pa[0].events = POLLIN | POLLPRI; pa[0].revents = 0; - if (poll_x(pa, 1, 0) > 0 + if (poll_x(pa, 1, 0) > 0 /* don't wait if there is nothing */ && (pa[0].revents == POLLIN - || pa[0].revents == POLLPRI)) { - char tb[3]; - if (read(STDIN_FILENO, tb, 1) > 0) { /* User hit a key */ - rv = tb[0] ; + || pa[0].revents == POLLPRI)) { /* Something is there */ + char tb[10]; + if (read(STDIN_FILENO, tb, 3) > 0) { /* Get it and any return */ + rv = tb[0]; } } - /* Restore stdin */ + /* Restore stdin if interactive */ if (!not_interactive && tcsetattr(STDIN_FILENO, TCSANOW, &origs) < 0) a1logw(g_log, "poll_con_char: tcsetattr failed with '%s' on stdin", strerror(errno)); return rv; } -/* Suck all characters from the keyboard */ -/* (If not_interactive, does nothing) */ +/* Discard all pending characters from stdin */ void empty_con_chars(void) { - if (not_interactive) - return; - tcflush(STDIN_FILENO, TCIFLUSH); } diff --git a/spectro/dispcal.c b/spectro/dispcal.c index 97b2d82d..a7fea2a1 100644 --- a/spectro/dispcal.c +++ b/spectro/dispcal.c @@ -1613,7 +1613,7 @@ void usage(int flag, char *diag, ...) { // fprintf(stderr," -q [vfmsu] Speed - Very Fast, Fast, Medium (def), Slow, Ultra Slow\n"); fprintf(stderr," -p Use telephoto mode (ie. for a projector, if available)\n"); fprintf(stderr," -a Use ambient mode (ie. for a projector, if available)\n"); - cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0); + cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0, 0); fprintf(stderr," -t [temp] White Daylight locus target, optional target temperaturee in deg. K (deflt.)\n"); fprintf(stderr," -T [temp] White Black Body locus target, optional target temperaturee in deg. K\n"); fprintf(stderr," -w x,y Set the target white point as chromaticity coordinates\n"); diff --git a/spectro/dispread.c b/spectro/dispread.c index 15e8d767..8e76a724 100644 --- a/spectro/dispread.c +++ b/spectro/dispread.c @@ -177,7 +177,7 @@ void usage(int flag, char *diag, ...) { } fprintf(stderr," -p Use telephoto mode (ie. for a projector, if available)\n"); fprintf(stderr," -a Use ambient measurement mode (ie. for a projector, if available)\n"); - cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0); + cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0, 0); fprintf(stderr," -k file.cal Load calibration file into display while reading\n"); fprintf(stderr," -K file.cal Apply calibration file to test values while reading\n"); #ifdef NT diff --git a/spectro/dispwin.c b/spectro/dispwin.c index 3198b9e5..8da6e900 100644 --- a/spectro/dispwin.c +++ b/spectro/dispwin.c @@ -3704,7 +3704,7 @@ static void dispwin_sighandler(int arg) { restore_display(pp); } - /* Call through to previous handler */ + /* Call through to previous handlers */ #ifdef UNIX if (arg == SIGHUP && dispwin_hup != SIG_DFL && dispwin_hup != SIG_IGN) dispwin_hup(arg); @@ -3718,15 +3718,34 @@ static void dispwin_sighandler(int arg) { exit(0); } +/* Use sigaction() if we can, to get SA_RESTART behavior */ +#if defined(UNIX) +//sighandler_t signal_x(int signum, sighandler_t handler) { +static void (*signal_x(int signum, void (*handler)(int)))(int) { + struct sigaction new, old; + int rv = 0; + + new.sa_handler = handler; + sigemptyset(&new.sa_mask); + new.sa_flags = SA_RESTART; + + rv = sigaction(signum, &new, &old); + + return old.sa_handler; +} +#else +# define signal_x signal +#endif + static void dispwin_install_signal_handlers(dispwin *p) { if (signal_dispwin == NULL) { /* Install the signal handler to ensure cleanup */ #ifdef UNIX - dispwin_hup = signal(SIGHUP, dispwin_sighandler); + dispwin_hup = signal_x(SIGHUP, dispwin_sighandler); #endif /* UNIX */ - dispwin_int = signal(SIGINT, dispwin_sighandler); - dispwin_term = signal(SIGTERM, dispwin_sighandler); + dispwin_int = signal_x(SIGINT, dispwin_sighandler); + dispwin_term = signal_x(SIGTERM, dispwin_sighandler); } /* Add this one to the list */ @@ -3742,10 +3761,10 @@ static void dispwin_uninstall_signal_handlers(dispwin *p) { signal_dispwin = p->next; if (signal_dispwin == NULL) { #if defined(UNIX) - signal(SIGHUP, dispwin_hup); + signal_x(SIGHUP, dispwin_hup); #endif /* UNIX */ - signal(SIGINT, dispwin_int); - signal(SIGTERM, dispwin_term); + signal_x(SIGINT, dispwin_int); + signal_x(SIGTERM, dispwin_term); } } else { dispwin *pp; diff --git a/spectro/ex1.c b/spectro/ex1.c index 680783a4..0e07dcd8 100644 --- a/spectro/ex1.c +++ b/spectro/ex1.c @@ -411,6 +411,17 @@ ex1_init_inst(inst *pp) { return inst_ok; } +static char *ex1_get_serial_no(inst *pp) { + ex1 *p = (ex1 *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serno; +} + /* Do a raw measurement. */ /* Will delete existing *praw */ /* return EX1 error */ @@ -1232,6 +1243,7 @@ extern ex1 *new_ex1(icoms *icom, instType dtype) { p->init_coms = ex1_init_coms; p->init_inst = ex1_init_inst; + p->get_serial_no = ex1_get_serial_no; p->capabilities = ex1_capabilities; p->meas_config = ex1_meas_config; p->check_mode = ex1_check_mode; diff --git a/spectro/huey.c b/spectro/huey.c index 2b79f8a1..98a3e85e 100644 --- a/spectro/huey.c +++ b/spectro/huey.c @@ -942,7 +942,7 @@ huey_read_all_regs( if ((ev = huey_rdreg_word(p, &p->ser_no, 0) ) != inst_ok) return ev; a1logd(p->log,4,"serial number = %d\n",p->ser_no); - + sprintf(p->serno, "%u",p->ser_no); /* LCD/user calibration values */ for (i = 0; i < 9; i++) { @@ -1170,6 +1170,17 @@ huey_init_inst(inst *pp) { return inst_ok; } +static char *huey_get_serial_no(inst *pp) { + huey *p = (huey *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serno; +} + /* Read a single sample */ /* Return the dtp error code */ static inst_code @@ -1758,6 +1769,7 @@ extern huey *new_huey(icoms *icom, instType dtype) { p->init_coms = huey_init_coms; p->init_inst = huey_init_inst; + p->get_serial_no = huey_get_serial_no; p->capabilities = huey_capabilities; p->check_mode = huey_check_mode; p->set_mode = huey_set_mode; diff --git a/spectro/huey.h b/spectro/huey.h index bf14c728..cc43ba4c 100644 --- a/spectro/huey.h +++ b/spectro/huey.h @@ -96,6 +96,7 @@ struct _huey { /* EEPROM registers */ /* Number is the register address, and B, S, W, F indicate the type/size */ int ser_no; /* Serial number */ + char serno[20]; /* Serial number as a string */ double LCD_cal[9]; /* LCD 3x3 calibration matrix */ int LCD_caltime; /* Calibration time in secs from January 1, 1970, UTC */ diff --git a/spectro/i1d3.c b/spectro/i1d3.c index 9227c0ab..be97bb63 100644 --- a/spectro/i1d3.c +++ b/spectro/i1d3.c @@ -1,4 +1,3 @@ - /* * Argyll Color Management System * @@ -577,31 +576,30 @@ i1d3_lock_status( static void create_unlock_response(unsigned int *k, unsigned char *c, unsigned char *r); - /* Unlock the device */ +static struct { + char *pname; /* Product name */ + unsigned int key[2]; /* ArgyllCMS flavor unlock code */ + i1d3_dtype btype; /* Base type enumerator */ + i1d3_dtype stype; /* Sub type enumerator */ +} i1d3_codes[] = { + { "i1Display3 ", { 0xe9622e9f, 0x8d63e133 }, i1d3_disppro, i1d3_disppro }, + { "Colormunki Display ", { 0xe01e6e0a, 0x257462de }, i1d3_munkdisp, i1d3_munkdisp }, + { "i1Display3 ", { 0xcaa62b2c, 0x30815b61 }, i1d3_disppro, i1d3_dpp_oem }, + { "i1Display3 ", { 0xa9119479, 0x5b168761 }, i1d3_disppro, i1d3_nec_ssp }, + { "i1Display3 ", { 0x160eb6ae, 0x14440e70 }, i1d3_disppro, i1d3_quato_sh3 }, + { "i1Display3 ", { 0x291e41d7, 0x51937bdd }, i1d3_disppro, i1d3_hp_dreamc }, + { "i1Display3 ", { 0x1abfae03, 0xf25ac8e8 }, i1d3_disppro, i1d3_wacom_dc }, + { "i1Display3 ", { 0x828c43e9, 0xcbb8a8ed }, i1d3_disppro, i1d3_tpa_1 }, + { NULL }, { NULL } +}; + static inst_code i1d3_unlock( i1d3 *p /* Object */ ) { unsigned char todev[64]; unsigned char fromdev[64]; - struct { - char *pname; /* Product name */ - unsigned int key[2]; /* Unlock code */ - i1d3_dtype btype; /* Base type enumerator */ - i1d3_dtype stype; /* Sub type enumerator */ - } codes[] = { - { "i1Display3 ", { 0xe9622e9f, 0x8d63e133 }, i1d3_disppro, i1d3_disppro }, - { "Colormunki Display ", { 0xe01e6e0a, 0x257462de }, i1d3_munkdisp, i1d3_munkdisp }, - { "i1Display3 ", { 0xcaa62b2c, 0x30815b61 }, i1d3_disppro, i1d3_dpp_oem }, - { "i1Display3 ", { 0xa9119479, 0x5b168761 }, i1d3_disppro, i1d3_nec_ssp }, - { "i1Display3 ", { 0x160eb6ae, 0x14440e70 }, i1d3_disppro, i1d3_quato_sh3 }, - { "i1Display3 ", { 0x291e41d7, 0x51937bdd }, i1d3_disppro, i1d3_hp_dreamc }, - { "i1Display3 ", { 0xc9bfafe0, 0x02871166 }, i1d3_disppro, i1d3_sc_c6 }, - { "i1Display3 ", { 0x1abfae03, 0xf25ac8e8 }, i1d3_disppro, i1d3_wacom_dc }, - { "i1Display3 ", { 0x828c43e9, 0xcbb8a8ed }, i1d3_disppro, i1d3_tpa_1 }, - { NULL } - }; inst_code ev; int ix, nix; @@ -609,7 +607,7 @@ i1d3_unlock( /* Count the keys */ for (nix = 0;;nix++) { - if (codes[nix].pname == NULL) + if (i1d3_codes[nix].pname == NULL) break; } @@ -617,7 +615,7 @@ i1d3_unlock( for (ix = 0;;ix++) { /* If we've run out of unlock keys */ - if (codes[ix].pname == NULL) { + if (i1d3_codes[ix].pname == NULL) { a1logw(p->log, "i1d3: Unknown lock code. Please contact ArgyllCMS for help\n"); return i1d3_interp_code((inst *)p, I1D3_UNKNOWN_UNLOCK); } @@ -625,16 +623,16 @@ i1d3_unlock( // return i1d3_interp_code((inst *)p, I1D3_UNLOCK_FAIL); /* Skip any keys that don't match the product name */ - if (strcmp(p->prod_name, codes[ix].pname) != 0) { - continue; - } +// if (strcmp(p->prod_name, i1d3_codes[ix].pname) != 0) { +// continue; +// } // a1logd(p->log, 3, "i1d3_unlock: Trying unlock key 0x%08x 0x%08x\n", -// codes[ix].key[0], codes[ix].key[1]); +// i1d3_codes[ix].key[0], i1d3_codes[ix].key[1]); a1logd(p->log, 3, "i1d3_unlock: Trying unlock key %d/%d\n", ix+1, nix); - p->btype = codes[ix].btype; - p->stype = codes[ix].stype; + p->btype = i1d3_codes[ix].btype; + p->stype = i1d3_codes[ix].stype; /* Attempt unlock */ memset(todev, 0, 64); @@ -645,14 +643,21 @@ i1d3_unlock( return ev; /* Convert challenge to response */ - create_unlock_response(codes[ix].key, fromdev, todev); + create_unlock_response(i1d3_codes[ix].key, fromdev, todev); /* Send the response */ if ((ev = i1d3_command(p, i1d3_lockresp, todev, fromdev, 1.0, 0)) != inst_ok) return ev; - if (fromdev[2] == 0x77) { /* Sucess */ - break; + if (fromdev[2] == 0x77) { /* Sucess ? */ + int stat; + + /* Check success */ + if ((ev = i1d3_lock_status(p,&stat)) != inst_ok) + return ev; + + if (stat == 0) + break; } a1logd(p->log, 3, "i1d3_unlock: Trying next unlock key\n"); @@ -939,7 +944,7 @@ i1d3_set_LEDs( and halve this to use as the quantization value (ie. make it lie between 20 and 80 Hz). - If there was no error, return refresh quanization period it. + If there was no error, return refresh quanization period. If there is no aparent refresh, or the refresh rate is not determinable, return a period of 0.0 and inst_ok; @@ -2582,6 +2587,9 @@ static int i1d3_diff_thread(void *pp) { static inst_code set_default_disp_type(i1d3 *p); + +static inst_code i1d3_bfsearch(i1d3 *p); + /* Initialise the I1D3 */ static inst_code i1d3_init_inst(inst *pp) { @@ -2622,9 +2630,11 @@ i1d3_init_inst(inst *pp) { if ((ev = i1d3_lock_status(p,&stat)) != inst_ok) return ev; + if (stat != 0) { /* Locked, so unlock it */ a1logd(p->log, 3, "i1d3_init_inst: unlocking the instrument\n"); + if ((ev = i1d3_unlock(p)) != inst_ok) return ev; if ((ev = i1d3_lock_status(p,&stat)) != inst_ok) @@ -2712,6 +2722,20 @@ i1d3_init_inst(inst *pp) { return ev; } +/* Return the instrument serial number. */ +/* (This will be an empty string if there is no serial no) */ +char *i1d3_get_serial_no( +inst *pp) { + i1d3 *p = (i1d3 *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serial_no; +} + /* Read a single sample */ /* Return the dtp error code */ static inst_code @@ -4071,6 +4095,41 @@ i1d3_get_set_opt(inst *pp, inst_opt_type m, ...) { } } +/* Look for an escape code (to escape from the clutches of the re-seller!) */ +/* Can only call this once. */ +static void get_escape_code(i1d3 *p) { + char *cp; + static eset = 0; + + if (eset) + return; + + if ((cp = getenv("I1D3_ESCAPE")) != NULL) { + int nix; + unsigned char k[8]; + + + if (sscanf(cp, "%2hx%2hx%2hx%2hx%2hx%2hx%2hx%2hx", + &k[0], &k[1], &k[2], &k[3], &k[4], &k[5], &k[6], &k[7]) != 8) + return; + + /* Find the last slot */ + for (nix = 0;;nix++) { + if (i1d3_codes[nix].pname == NULL) + break; + } + + i1d3_codes[nix].pname = "i1Display3 "; + i1d3_codes[nix].key[0] = (k[0] << 24) | (k[1] << 16) | (k[2] << 8) | k[3]; + i1d3_codes[nix].key[1] = (k[4] << 24) | (k[5] << 16) | (k[6] << 8) | k[7]; + i1d3_codes[nix].btype = i1d3_disppro; + i1d3_codes[nix].stype = i1d3_unk; + a1logd(p->log, 3, "i1d3: found escape code 0x%08x 0x%08x\n", + i1d3_codes[nix].key[0], i1d3_codes[nix].key[1]); + eset = 1; + } +} + /* Constructor */ extern i1d3 *new_i1d3(icoms *icom, instType dtype) { i1d3 *p; @@ -4084,6 +4143,7 @@ extern i1d3 *new_i1d3(icoms *icom, instType dtype) { p->init_coms = i1d3_init_coms; p->init_inst = i1d3_init_inst; + p->get_serial_no = i1d3_get_serial_no; p->capabilities = i1d3_capabilities; p->meas_config = i1d3_meas_config; p->check_mode = i1d3_check_mode; @@ -4113,11 +4173,12 @@ extern i1d3 *new_i1d3(icoms *icom, instType dtype) { icmSetUnity3x3(p->ccmat); p->dtech = disptech_unknown; + get_escape_code(p); + return p; } - /* Combine the 2 word key and 64 byte challenge into a 64 bit response. */ static void create_unlock_response(unsigned int *k, unsigned char *c, unsigned char *r) { int i; @@ -4200,3 +4261,5 @@ static void create_unlock_response(unsigned int *k, unsigned char *c, unsigned c r[24 + i] = c[2] ^ sr[i]; } + + diff --git a/spectro/i1d3.h b/spectro/i1d3.h index d1c61114..44abad35 100644 --- a/spectro/i1d3.h +++ b/spectro/i1d3.h @@ -87,9 +87,9 @@ typedef enum { i1d3_nec_ssp = 3, /* NEC SpectraSensor Pro */ i1d3_quato_sh3 = 4, /* Quato Silver Haze 3 */ i1d3_hp_dreamc = 5, /* HP DreameColor */ - i1d3_sc_c6 = 6, /* SpectraCal C6 */ i1d3_wacom_dc = 7, /* Wacom DC */ - i1d3_tpa_1 = 8 /* Toshiba TPA-1 */ + i1d3_tpa_1 = 8, /* Toshiba TPA-1 */ + i1d3_unk = 9 /* Unknown */ } i1d3_dtype; /* Generic OEM aliases: diff --git a/spectro/i1disp.c b/spectro/i1disp.c index a04e5b23..fb1ba164 100644 --- a/spectro/i1disp.c +++ b/spectro/i1disp.c @@ -2,7 +2,7 @@ /* * Argyll Color Management System * - * Gretag i1Display related functions + * Gretag i1Display 1/2/Smile related functions * * Author: Graeme W. Gill * Date: 18/10/2006 @@ -1547,6 +1547,7 @@ i1disp_read_all_regs( if ((ev = i1disp_rdreg_word(p, &p->reg0_W, 0) ) != inst_ok) return ev; a1logd(p->log, 3, "serial number = %d\n",p->reg0_W); + sprintf(p->serno, "%u",p->reg0_W); /* LCD/user calibration values */ for (i = 0; i < 9; i++) { @@ -1864,6 +1865,17 @@ i1disp_init_inst(inst *pp) { return inst_ok; } +static char *i1disp_get_serial_no(inst *pp) { + i1disp *p = (i1disp *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serno; +} + /* Read a single sample */ /* Return the dtp error code */ static inst_code @@ -2647,6 +2659,7 @@ extern i1disp *new_i1disp(icoms *icom, instType dtype) { p->init_coms = i1disp_init_coms; p->init_inst = i1disp_init_inst; + p->get_serial_no = i1disp_get_serial_no; p->capabilities = i1disp_capabilities; p->check_mode = i1disp_check_mode; p->set_mode = i1disp_set_mode; diff --git a/spectro/i1disp.h b/spectro/i1disp.h index 23418b60..80a6fa75 100644 --- a/spectro/i1disp.h +++ b/spectro/i1disp.h @@ -3,7 +3,7 @@ /* * Argyll Color Management System * - * Gretag i1Display related defines + * Gretag i1Display 1/2/Smile related defines * * Author: Graeme W. Gill * Date: 19/10/2006 @@ -174,7 +174,6 @@ struct _i1disp { int int_clocks; /* Currently set integration time in clocks */ - /* For dtype == 2 (ColorMunki Smile) */ char serno[20]; /* Ascii serial number */ /* misc */ diff --git a/spectro/i1pro.c b/spectro/i1pro.c index 274ede53..cbc49331 100644 --- a/spectro/i1pro.c +++ b/spectro/i1pro.c @@ -447,7 +447,7 @@ i1pro_interp_error(inst *pp, i1pro_code ec) { case I1PRO_RD_WHITEREADINCONS: return "White calibration reading is inconsistent"; case I1PRO_RD_WHITEREFERROR: - return "White reference reading error"; + return "White reference reading is out of tollerance"; case I1PRO_RD_LIGHTTOOLOW: return "Light level is too low"; case I1PRO_RD_LIGHTTOOHIGH: diff --git a/spectro/i1pro3_imp.c b/spectro/i1pro3_imp.c index 9bcbdb9d..1d307c56 100644 --- a/spectro/i1pro3_imp.c +++ b/spectro/i1pro3_imp.c @@ -1806,11 +1806,15 @@ i1pro3_code i1pro3_imp_measure( for (;;) { inst_code rc; i1pro3_eve; + int nerrs = 0; int cerr; if ((ev = i1pro3_waitfor_event_th(p, &ecode, 0.1)) != I1PRO3_OK - && ev != I1PRO3_INT_BUTTONTIMEOUT) - break; /* Error */ + && ev != I1PRO3_INT_BUTTONTIMEOUT) { + if (++nerrs < 5) + continue; /* Retry for more robustness */ + break; + } if (ev == I1PRO3_OK) break; /* event triggered */ @@ -5895,7 +5899,7 @@ i1pro3_code i1pro3_waitfor_event_th(i1pro3 *p, i1pro3_eve *ecode, double top) { amutex_unlock(m->lock); if ((rv = icoms2i1pro3_err(se)) != I1PRO3_OK) { - a1logd(p->log,1,"i1pro3_waitfor_event_th_th: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime); + a1logd(p->log,1,"i1pro3_waitfor_event_th_setup: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime); return rv; } @@ -12407,7 +12411,7 @@ static i1pro3_code i1pro3_zebra_proc( do_plot(t2p_t, t2p_p, NULL, NULL, ntrans); #endif // NEVER - /* Creae position to time mapping. We create a list in */ + /* Create position to time mapping. We create a list in */ /* increments of 0.2 mm and then add measurement samples */ /* that fall into each slot. */ @@ -12441,8 +12445,12 @@ static i1pro3_code i1pro3_zebra_proc( ps = vect_lerp2(t2p_t, t2p_p, tm, ntrans); slot = (int)floor(ps/POSRES + 0.5); - if (slot < 0 || slot >= npos) - error("Assert in %s at line %d slot %d outside 0 .. %d\n",__FILE__,__LINE__,slot,npos-1); + /* In case time period covered by zebra is different to time period of measurement... */ + if (slot < 0) + slot = 0; + else if (slot >= npos) + slot = npos-1; + //fprintf(stderr,"Sample %d time %f position %f slot %d\n",i,tm,ps,slot); if (p2m[slot][-1] >= p2m[slot][-2]) { int *ary; @@ -12758,6 +12766,7 @@ i1pro3_code i1pro3_do_measure( m->llamponoff = msec_time(); } + /* Set nummeas to the actual number of measurements */ if (refmode) { if (tint > 1) /* Round down to give number of whole measurements */ nummeas = (anummeas - nnskip)/(tint / 2); @@ -12917,18 +12926,20 @@ i1pro3_code i1pro3_do_measure( zskip = nnskip * (refmode ? 2 : 1) * m->minintclks; /* Copy zebra ruler bits into bytes */ - for (jj = ii = i = 0; i < m->zebra_bread; i++) { + for (jj = ii = i = 0; i < m->zebra_bread; i++) { /* For each byte */ unsigned int ival, oval; int k; ival = zbuf[i]; - for (k = 0; k < 4; k++, ii++) { + for (k = 0; k < 4; k++, ii++) { /* For each 2 bit */ oval = ival & 3; ival >>= 2; if (ii >= zskip) { - if (jj >= numzeb) + if (jj >= numzeb) { /* More than we expect */ + a1logd(p->log,6,"i1pro3_do_measure - more zebra bytes than measurements\n"); break; + } zeb[jj] = oval; jj++; } @@ -12940,9 +12951,17 @@ i1pro3_code i1pro3_do_measure( } free(zbuf); - if (jj != numzeb || i > m->zebra_bread || i < (m->zebra_bread - (2 * intclocks)/8)) { - error("Assert in %s at %d: zebra/meas mismatch: jj %d != numzeb %d or i %d != bread %d\n",__FILE__,__LINE__,jj,numzeb,i,m->zebra_bread); - } + /* It seems that sometimes we get fewer zebra bytes than expected for */ + /* the number of measurements. Adjust acordingly */ + if (jj < numzeb) { + a1logd(p->log,6,"i1pro3_do_measure - fewer zebra bytes than measurements\n"); +printf("~1 fewer zebra bytes than expected\n"); + numzeb = jj; + } + + if (i > m->zebra_bread || i < (m->zebra_bread - (2 * intclocks)/8)) { + error("Assert in %s at %d: zebra/meas mismatch: i %d != bread %d\n",__FILE__,__LINE__,jj,numzeb,i,m->zebra_bread); + } if (p->log->debug >= 9) { a1logd(p->log,9,"zebra raw data:\n"); diff --git a/spectro/i1pro_imp.h b/spectro/i1pro_imp.h index fdeb4b17..0f0aa140 100644 --- a/spectro/i1pro_imp.h +++ b/spectro/i1pro_imp.h @@ -404,7 +404,7 @@ void del_i1proimp(i1pro *p); #define I1PRO_RD_DARKNOTVALID 0x32 /* Dark reading is not valid (too light) */ #define I1PRO_RD_NEEDS_CAL 0x33 /* Mode needs calibration */ #define I1PRO_RD_WHITEREADINCONS 0x34 /* White reference readings are inconsistent */ -#define I1PRO_RD_WHITEREFERROR 0x35 /* White reference reading error */ +#define I1PRO_RD_WHITEREFERROR 0x35 /* White reference tollerance error */ #define I1PRO_RD_LIGHTTOOLOW 0x36 /* Light level is too low */ #define I1PRO_RD_LIGHTTOOHIGH 0x37 /* Light level is too high */ #define I1PRO_RD_SHORTMEAS 0x38 /* Measurment was too short */ diff --git a/spectro/inst.c b/spectro/inst.c index 1876f197..863a9d66 100644 --- a/spectro/inst.c +++ b/spectro/inst.c @@ -864,6 +864,7 @@ static inst_disptypesel *expand_dlist(inst_disptypesel *list, int nlist, int *na list[nlist].sel[0] = '\000'; list[nlist].desc[0] = '\000'; list[nlist].refr = 0; + list[nlist].dtech = 0; list[nlist].ix = 0; list[nlist].cc_cbid = 0; list[nlist].path = NULL; diff --git a/spectro/inst.h b/spectro/inst.h index 0b9f830c..9e28aa07 100644 --- a/spectro/inst.h +++ b/spectro/inst.h @@ -756,6 +756,7 @@ typedef struct _inst_meascondsel { void *event_cntx; /* Asynchronous event callback function */ \ athread *scan_ready_thread; /* msec_scan_ready() support */ \ int scan_ready_delay; /* msec_scan_ready() support */ \ + inst_code last_cal_ec; /* set by inst_handle_calibrate() when there is an error */ \ \ /* Virtual delete. Cleans up things done by new_inst(). */ \ inst_code (*vdel)( \ diff --git a/spectro/instappsup.c b/spectro/instappsup.c index f00df4e4..e351ff90 100644 --- a/spectro/instappsup.c +++ b/spectro/instappsup.c @@ -180,6 +180,8 @@ inst_code inst_handle_calibrate( a1logd(p->log,1,"inst_handle_calibrate called\n"); + p->last_cal_ec = 0; + /* Untill we're done with the calibration */ for (;;) { @@ -216,6 +218,8 @@ inst_code inst_handle_calibrate( printf("Calibration failed with '%s' (%s)\n", p->inst_interp_error(p, ev), p->interp_error(p, ev)); + p->last_cal_ec = ev; /* So caller can see what happened */ + if (doimmediately) return inst_user_abort; @@ -426,11 +430,14 @@ inst_code inst_handle_calibrate( /* Return accumulated capabilities2 of all the instruments */ /* Return all possible capabilities if there are no instruments */ /* If docbib is nz, then only display the base calibration display types */ -inst2_capability inst_show_disptype_options(FILE *fp, char *oline, icompaths *icmps, int docbib) { +/* If openallisnt is nz, then open even slow serial instruments for specific info. */ +inst2_capability inst_show_disptype_options(FILE *fp, char *oline, icompaths *icmps, + int docbib, int openallinst) { int i, j; char buf[200], *bp; char extra[40]; int olen, pstart; + int onlyidinst = 1; /* Only open instruments that can be id'd without opening */ int notall = 0; /* Not all instruments are USB */ int gotone = 0; /* Found at least one USB instrument */ inst2_capability acap = 0; /* Accumulate capabilities */ @@ -438,6 +445,9 @@ inst2_capability inst_show_disptype_options(FILE *fp, char *oline, icompaths *ic if (icmps == NULL) return 0; + if (openallinst) + onlyidinst = 0; /* Slowly ID and open all instrument */ + /* Locate the end of the option */ for (bp = oline; *bp != '\000' && *bp == ' '; bp++) ; @@ -456,7 +466,7 @@ inst2_capability inst_show_disptype_options(FILE *fp, char *oline, icompaths *ic inst2_capability cap; int k; - if ((it = new_inst(icmps->dpaths[dtix_inst][i], 1, g_log, NULL, NULL)) == NULL) { + if ((it = new_inst(icmps->dpaths[dtix_inst][i], onlyidinst, g_log, NULL, NULL)) == NULL) { notall = 1; continue; } diff --git a/spectro/instappsup.h b/spectro/instappsup.h index d045afb3..8e0bd58a 100644 --- a/spectro/instappsup.h +++ b/spectro/instappsup.h @@ -85,8 +85,10 @@ inst_code inst_handle_calibrate( /* A helper function to display -y flag usage for each instrument type available */ /* Return accumulated capabilities2 of all the instruments. */ -/* If docbib is nz, then only display the base calibration display types */ -inst2_capability inst_show_disptype_options(FILE *fp, char *oline, icompaths *icmps, int docbib); +/* If docbib is nz, then only display the base calibration display types. */ +/* If openallisnt is nz, then open even slow serial instruments for specific info. */ +inst2_capability inst_show_disptype_options(FILE *fp, char *oline, icompaths *icmps, + int docbib, int openallinst); /* A helper function to turn a -y flag into a list index */ /* If docbib is nz, then only allow base calibration display types */ diff --git a/spectro/instlib.ksh b/spectro/instlib.ksh index 47243e49..b60f5b5f 100755 --- a/spectro/instlib.ksh +++ b/spectro/instlib.ksh @@ -40,6 +40,10 @@ RSPL_FILES=" ../rspl/rspl1.c " +USB_FILES=" + ../usb/driver/driver_api.h + " + SPECTRO_FILES=" License2.txt spotread.c @@ -89,6 +93,10 @@ SPECTRO_FILES=" i1pro.c i1pro_imp.h i1pro_imp.c + i1pro3.h + i1pro3.c + i1pro3_imp.h + i1pro3_imp.c munki.h munki.c munki_imp.h @@ -101,6 +109,8 @@ SPECTRO_FILES=" colorhug.h spyd2.c spyd2.h + spydX.c + spydX.h specbos.h specbos.c kleink10.h @@ -137,7 +147,7 @@ SPECTRO_FILES=" xrga.c " -FILES=" $H_FILES $CGATS_FILES $NUMLIB_FILES $RSPL_FILES $XICC_FILES $SPECTRO_FILES " +FILES=" $H_FILES $CGATS_FILES $NUMLIB_FILES $RSPL_FILES $XICC_FILES $USB_FILES $SPECTRO_FILES " rm -f instlib.zip rm -rf _zipdir @@ -161,7 +171,9 @@ done # Plus renamed files cp IntsLib_Readme.txt _zipdir/instlib/Readme.txt echo instlib/Readme.txt >> _ziplist +cp Jamfile.SA _zipdir/instlib/Jamfile cp Makefile.SA _zipdir/instlib/Makefile +echo instlib/Jamfile >> _ziplist echo instlib/Makefile >> _ziplist cp ../h/aconfig.h _zipdir/instlib/sa_config.h echo instlib/sa_config.h >> _ziplist diff --git a/spectro/kleink10.c b/spectro/kleink10.c index d5485f97..f40464ff 100644 --- a/spectro/kleink10.c +++ b/spectro/kleink10.c @@ -557,6 +557,16 @@ k10_init_inst(inst *pp) { return inst_ok; } +static char *k10_get_serial_no(inst *pp) { + kleink10 *p = (kleink10 *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serial_no; +} /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -2886,6 +2896,7 @@ extern kleink10 *new_kleink10(icoms *icom, instType dtype) { p->init_coms = k10_init_coms; p->init_inst = k10_init_inst; p->capabilities = k10_capabilities; + p->get_serial_no = k10_get_serial_no; p->check_mode = k10_check_mode; p->set_mode = k10_set_mode; p->get_disptypesel = k10_get_disptypesel; diff --git a/spectro/linear.cal b/spectro/linear.cal index 5c95e570..048c35d7 100644 --- a/spectro/linear.cal +++ b/spectro/linear.cal @@ -2,7 +2,7 @@ CAL DESCRIPTOR "Argyll Device Calibration Curves" ORIGINATOR "Argyll synthcal" -CREATED "Thu Sep 16 04:12:31 2021" +CREATED "Thu Dec 23 20:48:19 2021" DEVICE_CLASS "DISPLAY" COLOR_REP "RGB" diff --git a/spectro/sa_conv.c b/spectro/sa_conv.c index 7d00bc01..45873282 100644 --- a/spectro/sa_conv.c +++ b/spectro/sa_conv.c @@ -287,6 +287,13 @@ void sa_Clamp3(double out[3], double in[3]) { out[i] = in[i] < 0.0 ? 0.0 : in[i]; } +/* Add two 3 vectors */ +void sa_Add3(double out[3], double in1[3], double in2[3]) { + out[0] = in1[0] + in2[0]; + out[1] = in1[1] + in2[1]; + out[2] = in1[2] + in2[2]; +} + /* Return the normal Delta E given two Lab values */ double sa_LabDE(double *Lab0, double *Lab1) { double rv = 0.0, tt; @@ -435,6 +442,28 @@ void sa_Yxy2XYZ(double *out, double *in) { /* - - - - - - - - - - - - - - - - - - - - - - - - */ +/* 32 bit linear congruent generator */ +/* generates number between 0 and 4294967295 */ +/* (From Knuth & H.W.Lewis) */ +#define PSRAND32L(S) ((S) * 1664525L + 1013904223L) + +/* Return a 32 bit number between 0 and 4294967295 */ +unsigned int +sa_rand32( /* Return 32 bit random number */ +unsigned int seed /* Optional seed. Non-zero re-initialized with that seed */ +) { + static unsigned int pval = 12345678; + + if (seed != 0) + pval = seed; + + pval = PSRAND32L(pval); + + return pval; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - */ + /* Object for computing RFC 1321 MD5 checksums. */ /* Derived from Colin Plumb's 1993 public domain code. */ diff --git a/spectro/sa_conv.h b/spectro/sa_conv.h index 29a453d1..fb79348b 100644 --- a/spectro/sa_conv.h +++ b/spectro/sa_conv.h @@ -121,6 +121,8 @@ 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); +void sa_Add3(double out[3], double in1[3], double in2[3]); + #define icColorSpaceSignature sa_ColorSpaceSignature #define icSigXYZData sa_SigXYZData #define icSigLabData sa_SigLabData @@ -178,11 +180,16 @@ void sa_Yxy2XYZ(double *out, double *in); #define icmInverse3x3 sa_Inverse3x3 #define icmTranspose3x3 sa_Transpose3x3 +#define icmSet3(d_ary, s_val) ((d_ary)[0] = (s_val), (d_ary)[1] = (s_val), \ + (d_ary)[2] = (s_val)) #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 icmAdd3 sa_Add3 +#define rand32 sa_rand32 + #define icmAry2XYZ(xyz, ary) ((xyz).X = (ary)[0], (xyz).Y = (ary)[1], (xyz).Z = (ary)[2]) #define icmLabDE sa_LabDE diff --git a/spectro/specbos.c b/spectro/specbos.c index da4d5ecf..6a5c6824 100644 --- a/spectro/specbos.c +++ b/spectro/specbos.c @@ -425,11 +425,12 @@ specbos_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { if (sscanf(buf, "spectrometer number: %d ",&val) == 1 || sscanf(buf, "%d ",&val) == 1) { a1logv(p->log, 1, " Spectrometer serial number: %d\n",val); - p->serno = val; + p->ser_no = val; } else { a1logv(p->log, 1, " Failed to parse serial number\n"); - p->serno = -1; + p->ser_no = -1; } + sprintf(p->serno, "%u",p->ser_no); p->gotcoms = 1; @@ -879,8 +880,8 @@ specbos_init_inst(inst *pp) { *sp = '\000'; a1logv(p->log, 1, " Firmware: %s\n",buf); - if (p->serno != -1) { - a1logv(p->log, 1, " Spectrometer serial number: %d\n",p->serno); + if (p->ser_no != -1) { + a1logv(p->log, 1, " Spectrometer serial number: %d\n",p->ser_no); } else { a1logv(p->log, 1, " Failed to parse serial number\n"); } @@ -900,6 +901,17 @@ specbos_init_inst(inst *pp) { return inst_ok; } +static char *specbos_get_serial_no(inst *pp) { + specbos *p = (specbos *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serno; +} + static inst_code specbos_imp_measure_set_refresh(specbos *p); static inst_code specbos_imp_set_refresh(specbos *p); @@ -2627,6 +2639,7 @@ extern specbos *new_specbos(icoms *icom, instType dtype) { p->init_coms = specbos_init_coms; p->init_inst = specbos_init_inst; p->capabilities = specbos_capabilities; + p->get_serial_no = specbos_get_serial_no; p->meas_config = specbos_meas_config; p->check_mode = specbos_check_mode; p->set_mode = specbos_set_mode; diff --git a/spectro/specbos.h b/spectro/specbos.h index 3f9ddbad..ee412344 100644 --- a/spectro/specbos.h +++ b/spectro/specbos.h @@ -173,7 +173,8 @@ struct _specbos { int maxtin_warn; /* NZ if conf:maxtin failure warning has been given */ - int serno; /* Spectrometer serial number */ + int ser_no; /* Spectrometer serial number */ + char serno[20]; /* Serial number as string */ }; typedef struct _specbos specbos; diff --git a/spectro/spotread.c b/spectro/spotread.c index e2d1b41c..819ddb91 100644 --- a/spectro/spotread.c +++ b/spectro/spotread.c @@ -67,6 +67,8 @@ #if !defined(NOT_ALLINSTS) || defined(EN_SPYD2) # include "spyd2.h" #endif +#include "i1pro.h" +#include "i1pro_imp.h" #if defined (NT) #include @@ -433,6 +435,8 @@ static inst_code uicallback(void *cntx, inst_ui_purp purp) { */ +int g_showallcals = 0; /* Show display calibrations even for serial instruments */ + void usage(char *diag, ...) { int i; @@ -483,7 +487,7 @@ usage(char *diag, ...) { fprintf(stderr," -a Use ambient measurement mode (absolute results)\n"); fprintf(stderr," -f Use ambient flash measurement mode (absolute results)\n"); fprintf(stderr," -rw Use reflection white point relative chromatically adjusted mode\n"); - cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0); + cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0, g_showallcals); #ifndef SALONEINSTLIB fprintf(stderr," -I illum Set simulated instrument illumination using FWA (def -i illum):\n"); fprintf(stderr," M0, M1, M2, A, C, D50, D50M2, D65, F5, F8, F10 or file.sp]\n"); @@ -545,6 +549,7 @@ usage(char *diag, ...) { 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 a Use Averaging mode (if available) aa, aaa for more.\n"); + fprintf(stderr," -Y y Show even serial instrument display calibration types in usage (slow!)\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"); @@ -1086,6 +1091,10 @@ int main(int argc, char *argv[]) { } else if (na[0] == 'L') { lampdrift = 2; + /* Show even serial instrument display calibration types */ + } else if (na[0] == 'y') { + g_showallcals = 1; + /* ~~~ i1pro2 test code ~~~ */ } else if (na[0] == 'U') { uvmode = 1; @@ -1232,6 +1241,7 @@ int main(int argc, char *argv[]) { error("Setting trigger mode failed with error :'%s' (%s)", it->inst_interp_error(it, rv), it->interp_error(it, rv)); + /* Initial lamp dritf check, final lamp drift check */ for (pass = 0; pass < 2; pass++) { ipatch val; double dl, maxdl = -100.0, de, maxde = -100.0; @@ -1247,6 +1257,20 @@ int main(int argc, char *argv[]) { ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL, doone); if (ev != inst_ok) { /* Abort or fatal error */ + if (pass == 0 && lampdrift == 2 && (it->last_cal_ec & inst_imask) == I1PRO_RD_WHITEREFERROR) { + int c; + + printf("White reference is out of tollerance - press 'c' to do remediation anyway\n"); + empty_con_chars(); + c = next_con_char(); + printf("'%c'\n",c); + if (c == 'c') { + remtime = 120.0; /* Maximum */ + goto remediate; + } else { + error("Lamp drift remediation aborted"); + } + } error("Got abort or error from calibration"); } } @@ -1315,7 +1339,8 @@ int main(int argc, char *argv[]) { remtime = 90.0; else if (maxde > 0.20) remtime = 120.0; - + +remediate:; if (remtime > 0.0) { printf("\nDoing %.0f seconds of remediation\n",remtime); // Do remediation */ @@ -2384,6 +2409,8 @@ int main(int argc, char *argv[]) { if (sp.spec_n <= 0) error("Save: Instrument didn't return spectral data"); + empty_con_chars(); + printf("\nEnter filename (ie. xxxx.sp): "); fflush(stdout); if (getns(buf, 500) != NULL && strlen(buf) > 0) { if(write_xspect(buf, val.mtype, val.mcond, &sp)) diff --git a/spectro/spyd2.c b/spectro/spyd2.c index 107bc06b..ae075fa2 100644 --- a/spectro/spyd2.c +++ b/spectro/spyd2.c @@ -3044,6 +3044,17 @@ spyd2_init_inst(inst *pp) { return inst_ok; } +static char *spyd2_get_serial_no(inst *pp) { + spyd2 *p = (spyd2 *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serno; +} + /* Read a single sample */ /* Return the dtp error code */ static inst_code @@ -4093,6 +4104,7 @@ extern spyd2 *new_spyd2(icoms *icom, instType dtype) { p->init_coms = spyd2_init_coms; p->init_inst = spyd2_init_inst; + p->get_serial_no = spyd2_get_serial_no; p->capabilities = spyd2_capabilities; p->check_mode = spyd2_check_mode; p->set_mode = spyd2_set_mode; diff --git a/spectro/spydX.c b/spectro/spydX.c index 138daefb..64930336 100644 --- a/spectro/spydX.c +++ b/spectro/spydX.c @@ -312,6 +312,11 @@ spydX_getCalibration( a1logd(p->log, 3, "spydX_getCalibration %d: called\n",cix); + if (cix < 0 || cix >= SPYDX_NOCALIBS) { + rv = spydX_interp_code((inst *)p, SPYDX_CIX_MISMATCH); + a1logd(p->log, 6, "spydX_getCalibration cix is out of range 0 .. %d\n",SPYDX_NOCALIBS-1); + } + send[0] = cix; se = spydX_command(p, 0xCB, send, 1, reply, 0x2A, 1, 5.0); @@ -683,8 +688,8 @@ spydX_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) { a1logd(p->log, 2, "spydX_init_coms: about to init USB\n"); -// usbflags |= icomuf_no_open_clear; -// usbflags |= icomuf_resetep_before_read; + /* Some instruments on some systems to lockup after use... */ + usbflags |= icomuf_reset_before_close; /* Set config, interface, write end point, read end point */ /* ("serial" end points aren't used - the spydX uses USB control & write/read) */ @@ -902,16 +907,18 @@ static inst_code spydX_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_t inst_cal_type a_cals = inst_calt_none; if ((curtime - p->bdate) > DCALTOUT) { - a1logd(p->log,2,"Invalidating black cal as %d secs from last cal\n",curtime - p->bdate); + a1logd(p->log,2,"SpydX: Invalidating black cal as %d secs from last cal\n",curtime - p->bdate); p->bcal_done = 0; } - if (!IMODETST(p->mode, inst_mode_emis_ambient)) { + if (!IMODETST(p->mode, inst_mode_emis_ambient)) { /* If not ambient */ if (!p->bcal_done || !p->noinitcalib) n_cals |= inst_calt_emis_offset; a_cals |= inst_calt_emis_offset; } + a1logd(p->log,4,"SpydX: returning n_cals 0x%x, a_cals 0x%x\n",n_cals,a_cals); + if (pn_cals != NULL) *pn_cals = n_cals; @@ -978,6 +985,7 @@ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */ return ev; p->bcal_done = 1; p->bdate = cdate; + p->noinitcalib = 1; /* Don't calibrate again */ } #ifdef ENABLE_NONVCAL @@ -1250,7 +1258,7 @@ static inst_code set_disp_type(spydX *p, inst_disptypesel *dentry) { if (dentry->flags & inst_dtflags_ccmx) { if (dentry->cc_cbid != 1) { - a1loge(p->log, 1, "k10: matrix must use cbid 1!\n",dentry->cc_cbid); + a1loge(p->log, 1, "SpydX: matrix must use cbid 1 (is %d)!\n",dentry->cc_cbid); return inst_wrong_setup; } @@ -1258,11 +1266,15 @@ static inst_code set_disp_type(spydX *p, inst_disptypesel *dentry) { icmCpy3x3(p->ccmat, dentry->mat); p->cbid = 0; /* Can't be a base type now */ - } else { + } else if ((dentry->flags & inst_dtflags_mtx) != 0) { p->dtech = dentry->dtech; icmCpy3x3(p->ccmat, dentry->mat); p->cbid = dentry->cbid; p->ucbid = dentry->cbid; /* This is underying base if dentry is base selection */ + + } else { /* This shouldn't happen... */ + a1loge(p->log, 1, "SpydX: calibration selected isn't builit in or CCMX!\n"); + return inst_wrong_setup; } p->ix = dentry->ix; /* Native index */ diff --git a/spectro/spydX.h b/spectro/spydX.h index d9bbe2f5..73891c6c 100644 --- a/spectro/spydX.h +++ b/spectro/spydX.h @@ -116,7 +116,7 @@ struct _spydX { inst_disptypesel *dtlist; /* Display Type list */ int ndtlist; /* Number of valid dtlist entries */ - calinfo cinfo[SPYDX_NOCALIBS]; /* cal & meas setup info indexed by native ix */ + calinfo cinfo[SPYDX_NOCALIBS]; /* cal & meas setup info indexed by native ix */ int ix; /* current native cal index */ int cbid; /* current calibration base ID, 0 if not a base */ @@ -125,11 +125,11 @@ struct _spydX { double ccmat[3][3]; /* Current colorimeter correction matrix, unity if none */ - int bcal_done; + int bcal_done; /* Black offset calibration is valid */ int bcal[3]; /* Black offset calibration values */ time_t bdate; /* Date/time of last black calibration */ - int noinitcalib; /* Don't do initial calibrate */ + int noinitcalib; /* Don't do initial calibrate, or we've done initial calib. */ int lo_secs; /* Seconds since last opened (from calibration file mod time) */ }; typedef struct _spydX spydX; diff --git a/spectro/ss.c b/spectro/ss.c index 66dfc7e4..1368a342 100644 --- a/spectro/ss.c +++ b/spectro/ss.c @@ -509,7 +509,7 @@ ss_init_inst(inst *pp) { if ((rv = so_do_ExecWhiteRefToOrigDat(p)) != inst_ok) return rv; - if (p->log->verb) { + { char dn[19]; /* device name */ ss_dnot dno; /* device number */ char pn[9]; /* part number */ @@ -530,12 +530,16 @@ ss_init_inst(inst *pp) { &tt, &fswl, &nosw, &dsw)) != inst_ok) return rv; - a1logv(p->log, 1, + sprintf(p->serno, "%u",sn); + + if (p->log->verb) { + a1logv(p->log, 1, "Device: %s\n" "Serial No: %u\n" "Part No: %s\n" "Prod Date: %d/%d/%d\n" "SW Version: %s\n", dn, sn, pn, dp, mp, yp, sv); + } } /* Set the default colorimetric parameters */ @@ -556,6 +560,17 @@ ss_init_inst(inst *pp) { return inst_ok; } +static char *ss_get_serial_no(inst *pp) { + ss *p = (ss *)pp; + + if (!pp->gotcoms) + return ""; + if (!pp->inited) + return ""; + + return p->serno; +} + /* For an xy instrument, release the paper */ /* Return the inst error code */ static inst_code @@ -2124,6 +2139,7 @@ extern ss *new_ss(icoms *icom, instType dtype) { p->init_coms = ss_init_coms; p->init_inst = ss_init_inst; p->capabilities = ss_capabilities; + p->get_serial_no = ss_get_serial_no; p->check_mode = ss_check_mode; p->set_mode = ss_set_mode; p->get_set_opt = ss_get_set_opt; diff --git a/spectro/ss.h b/spectro/ss.h index 4fdded31..36ddef2d 100644 --- a/spectro/ss.h +++ b/spectro/ss.h @@ -63,6 +63,8 @@ struct _ss { inst_mode nextmode; /* Next requested mode */ inst_mode mode; /* Currently instrument mode */ + char serno[20]; /* Serial number */ + /* Desired measurement configuration */ ss_aft filt; /* Filter type (None/UV/D65/Pol etc.) */ ss_dst dstd; /* Density standard (ANSI A/ANSI T/DIN etc.) */ diff --git a/spectro/strange.cal b/spectro/strange.cal index 2fa447fd..1e38f1c1 100644 --- a/spectro/strange.cal +++ b/spectro/strange.cal @@ -2,7 +2,7 @@ CAL DESCRIPTOR "Argyll Device Calibration Curves" ORIGINATOR "Argyll synthcal" -CREATED "Thu Sep 16 04:12:31 2021" +CREATED "Thu Dec 23 20:48:19 2021" DEVICE_CLASS "DISPLAY" COLOR_REP "RGB" diff --git a/spectro/usbio.c b/spectro/usbio.c index 0e9e71fc..f4c9abec 100644 --- a/spectro/usbio.c +++ b/spectro/usbio.c @@ -299,7 +299,7 @@ static void icoms_sighandler(int arg) { in_usb_rw = -1; icoms_cleanup(); - /* Call the existing handlers */ + /* Call through to previous handlers */ #ifdef UNIX if (arg == SIGHUP && usbio_hup != SIG_DFL && usbio_hup != SIG_IGN) usbio_hup(arg); @@ -317,15 +317,34 @@ static void icoms_sighandler(int arg) { /* - - - - - - - - - - - - - - - - - - - */ +/* Use sigaction() if we can, to get SA_RESTART behavior */ +#if defined(UNIX) +//sighandler_t signal_x(int signum, sighandler_t handler) { +static void (*signal_x(int signum, void (*handler)(int)))(int) { + struct sigaction new, old; + int rv = 0; + + new.sa_handler = handler; + sigemptyset(&new.sa_mask); + new.sa_flags = SA_RESTART; + + rv = sigaction(signum, &new, &old); + + return old.sa_handler; +} +#else +# define signal_x signal +#endif + /* Install the cleanup signal handlers */ void usb_install_signal_handlers(icoms *p) { if (icoms_list == NULL) { a1logd(g_log, 6, "usb_install_signal_handlers: called\n"); #if defined(UNIX) - usbio_hup = signal(SIGHUP, icoms_sighandler); + usbio_hup = signal_x(SIGHUP, icoms_sighandler); #endif /* UNIX */ - usbio_int = signal(SIGINT, icoms_sighandler); - usbio_term = signal(SIGTERM, icoms_sighandler); + usbio_int = signal_x(SIGINT, icoms_sighandler); + usbio_term = signal_x(SIGTERM, icoms_sighandler); } /* Add it to our static list, to allow automatic cleanup on signal */ @@ -343,10 +362,10 @@ void usb_delete_from_cleanup_list(icoms *p) { icoms_list = p->next; if (icoms_list == NULL) { #if defined(UNIX) - signal(SIGHUP, usbio_hup); + signal_x(SIGHUP, usbio_hup); #endif /* UNIX */ - signal(SIGINT, usbio_int); - signal(SIGTERM, usbio_term); + signal_x(SIGINT, usbio_int); + signal_x(SIGTERM, usbio_term); } } else { icoms *pp; diff --git a/spectro/usbio_lx.c b/spectro/usbio_lx.c index 2aa0545b..ae1b5279 100644 --- a/spectro/usbio_lx.c +++ b/spectro/usbio_lx.c @@ -86,7 +86,7 @@ char *dpath /* path to device */ struct usb_idevice *usbd = NULL; int fd; /* device file descriptor */ - a1logd(log, 6, "usb_check_and_add: givem '%s'\n",dpath); + a1logd(log, 6, "usb_check_and_add: given '%s'\n",dpath); /* Open the device so that we can read it */ if ((fd = open(dpath, O_RDONLY)) < 0) { @@ -603,7 +603,7 @@ typedef struct _usbio_req { /* - - - - - - - - - - - - - - - - - - - - - */ -/* Cancel a req's urbs from the last down to but not including thisurb. */ +/* Cancel a req's urbs from the last down to but not including this urb. */ /* return icom error */ static int cancel_req(icoms *p, usbio_req *req, int thisurb) { int i, rv = ICOM_OK; @@ -615,7 +615,7 @@ static int cancel_req(icoms *p, usbio_req *req, int thisurb) { ev = ioctl(p->usbd->fd, USBDEVFS_DISCARDURB, &req->urbs[i].urb); if (ev != 0 && ev != EINVAL) { /* Hmmm */ - a1loge(p->log, ICOM_SYS, "cancel_req: failed with %d\n",rv); + a1logd(p->log, 2, "cancel_req: failed with %d\n",ev); rv = ICOM_SYS; } req->urbs[i].urb.status = -ECONNRESET; @@ -714,7 +714,7 @@ static void *urb_reaper(void *context) { /* If urb failed or is done (but not cancelled), cancel all the following urbs */ if (req->nourbs > 0 && !req->cancelled - && ((out->actual_length < out->buffer_length) + && ((out->actual_length < out->buffer_length) /* Run out of data */ || (out->status < 0 && out->status != -ECONNRESET))) { a1logd(p->log, 8, "urb_reaper: reaper canceling failed or done urb's\n",rv); if (cancel_req(p, req, iurb->urbno) != ICOM_OK) { diff --git a/spectro/usbio_nt.c b/spectro/usbio_nt.c index c9f3419c..5a65e962 100644 --- a/spectro/usbio_nt.c +++ b/spectro/usbio_nt.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include "driver_api.h" #undef DEBUG /* Turn on debug messages */ diff --git a/usb/55-Argyll.rules b/usb/55-Argyll.rules index 110dfae9..757d313e 100644 --- a/usb/55-Argyll.rules +++ b/usb/55-Argyll.rules @@ -135,9 +135,10 @@ ATTRS{idVendor}=="2457", ATTRS{idProduct}=="4000", ENV{COLORD_SENSOR_KIND}="ex1" ######################################################### # Set ID_VENDOR and ID_MODEL acording to VID and PID -#TEST=="/lib/udev/usb-db", IMPORT{program}="usb-db %p" +# Try to remain backwards compatible with older systems... 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" +ENV{COLORD_SENSOR_KIND}=="*?", TEST=="/lib/udev/usb-db", ENV{ID_MODEL_FROM_DATABASE}=="", IMPORT{program}="usb-db %p" +ENV{COLORD_SENSOR_KIND}=="*?", ENV{ID_MODEL_FROM_DATABASE}=="", IMPORT{builtin}="hwdb --subsystem=usb" # 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. diff --git a/usb/ArgyllCMS.cat b/usb/ArgyllCMS.cat index 1cccdb89a2a7ee1c775810321765cebadc4929b6..5284a42f8ca42c69ee1eb34bde8b748dbba88b02 100644 GIT binary patch delta 41 xcmZpdZI_+kELXWCKfHeR1Mg+a^gZPYW?vTPH8M0bGBP$YFflhU+nA`v2LMRk4f+58 delta 41 xcmZpdZI_+kEN8dnbM4unT&J$Nx6HlwOuH-2Yh-9(X=r9(Y-nI?vN2JO4**{W4&(p; diff --git a/usb/ArgyllCMS_x64.cat b/usb/ArgyllCMS_x64.cat index e418e9fae3c53ea611d6c6cd3e0328b36c260991..db079f41538f4e8cd4e57d07fd0fb6ea053dea5f 100644 GIT binary patch delta 41 xcmew^^Ic|wvz+w(X4BaREZwJH?4NCZ&%#HX*T~S&$jI2pz{K3ZY-6Gr9{^-v4u}8% delta 41 xcmew^^Ic|wv)t+%+{>1UzjN#@_}*`NbLk{;UL!*TOG7gQV?zUDlZ}aDd;o$E54ZpT diff --git a/xicc/Jamfile b/xicc/Jamfile index 02b24a4b..4cb21b8f 100644 --- a/xicc/Jamfile +++ b/xicc/Jamfile @@ -127,7 +127,8 @@ Main specsubsamp : specsubsamp.c ; Main specplot : specplot.c ; # CAM test routines -Main cam97test : cam97test.c ; +Main bluelin : bluelin.c ; +Main cam02test : cam02test.c ; Main cam02test : cam02test.c ; # Test utility for moncurve diff --git a/xicc/afiles b/xicc/afiles index 09a42098..986890ba 100644 --- a/xicc/afiles +++ b/xicc/afiles @@ -51,6 +51,7 @@ cam02.h cam02ref.h cam02test.c cam02plot.c +bluelin.c tm3015.h tm3015.c moncurve.c diff --git a/xicc/bluelin.c b/xicc/bluelin.c new file mode 100644 index 00000000..a5b8c1d4 --- /dev/null +++ b/xicc/bluelin.c @@ -0,0 +1,407 @@ + +/* + * International Color Consortium color transform expanded support + * + * Author: Graeme W. Gill + * Date: 23/22/2021 + * Version: 1.00 + * + * Copyright 2011-2021 Graeme W. Gill + * All rights reserved. + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + * + */ + +/* + * Test/development code for the cicam02 blue linearization hack. + * + * Inspired by "Color gamut mapping in a hue-linearized CIELAB color space" + * by Gustav Braun and Mark Fairchild. + */ + + +#include +#include +#include "aconfig.h" +#include "icc.h" +#include "numlib.h" +#include "plot.h" +#include "xcam.h" +#include "cam02.h" +//#include "xicc.h" +#include "ui.h" + +#define BLUELIN_h0 210.0 /* Low limit of hue angle to tweak */ +#define BLUELIN_h1 330.0 /* High limit of hue angle at C0 to tweak */ +#define BLUELIN_C0 50.0 /* Low limit of Chroma to tweak */ +#define BLUELIN_C10 80.0 /* High end of Chroma to tweak */ +#define BLUELIN_C11 140.0 /* High end of Hue and Chroma to tweak */ +#define BLUELIN_AMNT 0.60 /* Amount to tweak hue (< 1.0 increases tweak) */ + +/* We are using simple linear interpolation for this. */ +static void bluelin_fwd(double out[3], double in[3]) { + double J, C, h; + + C = sqrt(in[1] * in[1] + in[2] * in[2]); + h = (180.0/DBL_PI) * atan2(in[2], in[1]); + h = (h < 0.0) ? h + 360.0 : h; + + if (h >= BLUELIN_h0 && h <= BLUELIN_h1 + && C > BLUELIN_C0) { + double hh = (h - BLUELIN_h0)/(BLUELIN_h1 - BLUELIN_h0); + double gr, c1, amnt; + + c1 = (1.0 - hh) * BLUELIN_C10 + hh * BLUELIN_C11; + + gr = (C - BLUELIN_C0)/(c1 - BLUELIN_C0); + if (gr < 0.0) + gr = 0.0; + else if (gr > 1.0) + gr = 1.0; + + amnt = (1.0 - gr) * 1.0 + gr * BLUELIN_AMNT; + + if (hh < 0.5) { + hh = hh * amnt; + } else { + hh = (0.5 * amnt) + (hh - 0.5) * (1.0 - 0.5 * amnt)/0.5; + } + + h = BLUELIN_h0 + hh * (BLUELIN_h1 - BLUELIN_h0); + } + + h = DBL_PI/180.0 * h; + out[0] = in[0]; + out[1] = C * cos(h); + out[2] = C * sin(h); +} + +static void bluelin_bwd(double out[3], double in[3]) { + double J, C, h; + + C = sqrt(in[1] * in[1] + in[2] * in[2]); + h = (180.0/DBL_PI) * atan2(in[2], in[1]); + h = (h < 0.0) ? h + 360.0 : h; + + if (h >= BLUELIN_h0 && h <= BLUELIN_h1 + && C > BLUELIN_C0) { + double hh = (h - BLUELIN_h0)/(BLUELIN_h1 - BLUELIN_h0); + double ho = hh; + double gr, c1 = 0.0, pc1 = -100.0, amnt; + int j; + + /* Should be able to compute inverse analytically, but for the moment */ + /* we'll simply itterate to sufficient accuracy... */ + for (j = 0; fabs(c1 - pc1) > 0.02 && j < 20; j++) { + pc1 = c1; + c1 = (1.0 - ho) * BLUELIN_C10 + ho * BLUELIN_C11; + + gr = (C - BLUELIN_C0)/(c1 - BLUELIN_C0); + if (gr < 0.0) + gr = 0.0; + else if (gr > 1.0) + gr = 1.0; + + amnt = (1.0 - gr) * 1.0 + gr * BLUELIN_AMNT; + + if (hh < (0.5 * amnt)) { + ho = hh / amnt; + } else { + ho = 0.5 + (hh - 0.5 * amnt) * (1.0 - 0.5)/(1.0 - 0.5 * amnt); + } + } + h = BLUELIN_h0 + ho * (BLUELIN_h1 - BLUELIN_h0); + } + + h = DBL_PI/180.0 * h; + out[0] = in[0]; + out[1] = C * cos(h); + out[2] = C * sin(h); +} + +typedef double xyzarray[3]; + +xyzarray bandh[]; +xyzarray eandf[]; + +int +main(void) { + double in[3], lin[3], out[3]; + double C, h; + cam02 *cam; + plot_g _g, *g = &_g; + double x1, y1; + double maxde = 0.0; + int hstart = 0; + int i, j; + float black[3] = { 0.0, 0.0, 0.0 }; + + init_g(g); + + /* Explore effect and check it inverts */ + + for (h = 0.0; h <= 360.0; h += 10.0) { + for (C = 0.0; C <= 150.0; C += 2.0) { + double de; + + in[0] = 50.0; + in[1] = C; + in[2] = h; + icmLCh2Lab(in, in); + + bluelin_fwd(lin, in); + bluelin_bwd(out, lin); + + icmLab2LCh(in, in); + icmLab2LCh(lin, lin); + icmLab2LCh(out, out); + + /* We're plotting hue, Chromaticity */ + if (C > 0.0) { + add_vec_g(g, x1, y1, lin[2], lin[1], NULL); + x1 = lin[2]; + y1 = lin[1]; + } else { + x1 = h; + y1 = C; + } + + de = icmNorm33(in, out); + if (de > maxde) + maxde = de; + + if (de > 0.01) { + printf("%f %f %f -> %f %f %f de %f\n", in[0], in[1], in[2], out[0], out[1], out[2]); + } + } + } + + printf("Maxde = %f\n",maxde); + printf("Hue transformation:\n"); + do_plot_g(g, 0.0, 0.0, 0.0, 0.0, 1.0, 0, 1); + clear_g(g); + + /* Plot the constant hue data */ + cam = new_cam02(); + /* Data has D65 white point */ + cam->set_view(cam, vc_average, icmD65_ary3, 33, 0.2, 0.0, 0.0, 0.0, icmD65_ary3, 0, 0.0, 0.0, NULL); + cam->bluelin = 0; /* Turn off built in version */ + +#ifndef NEVER + hstart = 0; + for (i = 0; ; i++) { + double xyz[3], Jab[3]; + + if (bandh[i][1] < 0.0) + break; + + if (bandh[i][1] == 0.0) { + hstart = 1; + } + + icmScale3(xyz, bandh[i], 0.01); + cam->XYZ_to_cam(cam, Jab, xyz); + bluelin_fwd(Jab, Jab); + if (hstart) { + x1 = Jab[1]; + y1 = Jab[2]; + hstart = 0; + } else { + add_vec_g(g, x1, y1, Jab[1], Jab[2], NULL); + x1 = Jab[1]; + y1 = Jab[2]; + } +// add_sym_g(g, Jab[1], Jab[2], plotDiamond, black, NULL); + } + + printf("Berns and Hung::\n"); + do_plot_g(g, 0.0, 0.0, 0.0, 0.0, 1.0, 0, 1); + clear_g(g); +#endif // NEVER + + +#ifndef NEVER + hstart = 0; + for (i = 0; ; i++) { + double xyz[3], Jab[3]; + + if (eandf[i][1] < 0.0) + break; + + if (eandf[i][1] == 0.0) { + hstart = 1; + } + + icmScale3(xyz, eandf[i], 0.01); + cam->XYZ_to_cam(cam, Jab, xyz); + bluelin_fwd(Jab, Jab); + if (hstart) { + x1 = Jab[1]; + y1 = Jab[2]; + hstart = 0; + } else { + add_vec_g(g, x1, y1, Jab[1], Jab[2], NULL); + x1 = Jab[1]; + y1 = Jab[2]; + } + } + + printf("Ebner and Fairchil:\n"); + do_plot_g(g, 0.0, 0.0, 0.0, 0.0, 1.0, 0, 1); + clear_g(g); +#endif + + return 0; +} + +/* Constant hue reference data */ +/* 0,0,0 marks start of a hue */ +/* -1,-1,-1 marks end of data */ + +/* Berns and Hung (1995) data set, table IV, variable luminance */ +xyzarray bandh[] = { + 0,0,0, + 4.74,2.99,0.48, + 10.36,6.24,0.95, + 19.13,11.25,1.19, + 32.06,18.42,2.00, + 49.21,28.12,2.58, + 59.12,40.75,14.70, + 68.39,56.68,35.70, + 82.47,76.30,68.26, + 54.45,30.90,2.54, + 0,0,0, + 3.48,2.99,0.85, + 7.24,6.24,1.49, + 12.97,11.25,2.34, + 20.97,18.42,3.40, + 31.96,28.12,4.78, + 45.10,40.75,5.83, + 62.88,56.68,7.85, + 77.59,76.30,41.69, + 68.22,61.38,7.91, + 0,0,0, + 3.04,2.99,0.83, + 6.24,6.24,1.41, + 10.62,11.25,2.05, + 16.55,18.42,3.00, + 25.72,28.12,4.52, + 36.51,40.75,6.30, + 49.80,56.68,8.62, + 65.79,76.30,11.49, + 86.15,100.41,14.92, + 0,0,0, + 2.55,2.99,0.60, + 5.07,6.24,1.11, + 8.99,11.25,1.82, + 14.15,18.42,3.04, + 20.85,28.12,4.57, + 29.27,40.75,6.77, + 40.71,56.68,9.19, + 53.86,76.30,12.42, + 65.62,94.72,15.28, + 0,0,0, + 1.81,2.99,0.68, + 3.19,6.24,1.44, + 5.99,11.25,2.77, + 9.31,18.42,4.10, + 14.29,28.12,6.38, + 20.22,40.75,8.20, + 27.52,56.68,10.67, + 36.43,76.30,14.41, + 35.93,77.65,13.93, + 0,0,0, + 2.03,2.99,4.54, + 4.21,6.24,9.44, + 7.36,11.25,15.44, + 11.98,18.42,25.00, + 17.52,28.12,33.65, + 24.98,40.75,45.66, + 34.39,56.68,61.34, + 45.77,76.30,79.24, + 50.38,84.76,86.02, + 0,0,0, + 2.64,2.99,6.14, + 5.18,6.24,12.38, + 8.99,11.25,21.68, + 14.05,18.42,34.08, + 21.06,28.12,51.05, + 29.14,40.75,69.47, + 39.60,56.68,93.01, + 56.89,76.30,116.12, + 49.55,72.27,114.91, + 0,0,0, + 2.87,2.99,7.64, + 5.88,6.24,16.11, + 10.23,11.25,28.98, + 15.91,18.42,46.23, + 24.24,28.12,70.16, + 33.44,40.75,98.09, + 48.22,56.68,108.94, + 70.64,76.30,113.17, + 37.25,45.26,111.12, + 0,0,0, + 5.20,2.99,23.94, + 11.35,6.24,54.22, + 20.31,11.25,96.15, + 22.80,18.42,92.90, + 30.05,28.12,101.82, + 39.46,40.75,105.02, + 53.22,56.68,107.06, + 71.87,76.30,109.79, + 21.68,10.77,105.09, + 0,0,0, + 5.27,2.99,8.50, + 11.40,6.24,21.73, + 20.97,11.25,43.13, + 34.75,18.42,78.57, + 47.15,28.12,107.15, + 55.18,40.75,109.58, + 66.66,56.68,111.96, + 79.84,76.30,115.40, + 44.79,23.30,105.63, + 0,0,0, + 5.26,2.99,5.82, + 11.20,6.24,14.50, + 20.53,11.25,27.51, + 33.79,18.42,45.88, + 51.91,28.12,75.26, + 70.08,40.75,105.76, + 76.29,56.68,110.69, + 85.39,76.30,114.39, + 68.73,36.83,106.85, + 0,0,0, + 11.06,6.24,10.47, + 19.96,11.25,16.62, + 32.72,18.42,25.91, + 50.38,28.12,40.77, + 68.29,40.75,65.68, + 77.47,56.68,86.26, + 88.50,76.30,104.63, + 64.36,35.53,53.66, + 65.64,35.53,45.43, + -1,-1,-1 +}; + +/* Ebner and Fairchild (1998) set */ +xyzarray eandf[] = { +0,0,0, 2.4951, 1.9086, 2.0329, 3.3296, 1.9086, 2.1063, 5.7386, 2.9891, 3.2447, 7.3706, 6.2359, 7.0514, 9.0418, 6.2359, 6.8901, 10.9443, 6.2359, 6.7881, 12.0597, 6.2359, 6.6805, 21.6475, 11.251, 12.3602, 20.4172, 18.4187, 20.1965, 23.6417, 18.4187, 20.1739, 27.1865, 18.4187, 19.5653, 31.0729, 18.4187, 19.715, 35.5801, 18.4187, 18.1154, 52.2309, 28.1233, 30.6758, 43.6118, 40.7494, 44.221, 48.8989, 40.7494, 44.8546, 54.6008, 40.7494, 44.2074, 59.4653, 40.7494, 45.0086, 69.1717, 56.6813, 61.9143, 80.3849, 76.3034, 83.6166, +0,0,0, 2.3295, 2.9891, 1.2151, 5.0776, 6.2359, 3.235, 4.5813, 6.2359, 1.0648, 12.3217, 14.5417, 9.1954, 11.1245, 14.5417, 4.5894, 13.1275, 18.4187, 2.587, 24.2342, 28.1233, 20.1576, 22.2813, 28.1233, 12.0243, 20.4891, 28.1233, 6.415, 20.0979, 28.1233, 4.006, 42.0356, 48.2781, 37.6153, 39.2198, 48.2781, 24.84, 36.5407, 48.2781, 15.3761, 34.4596, 48.2781, 8.4394, 40.0128, 56.6813, 8.182, 52.6749, 76.3034, 11.314, 67.2532, 76.3034, 62.5084, 62.8152, 76.3034, 44.9196, 58.6004, 76.3034, 30.9764, 55.5877, 76.3034, 19.4968, +0,0,0, 2.057, 2.9891, 1.6832, 1.3952, 2.9891, 0.8032, 8.6184, 11.251, 8.5273, 6.9267, 11.251, 5.3448, 5.5532, 11.251, 2.8928, 8.2777, 18.4187, 4.1966, 22.8649, 28.1233, 23.4216, 19.4735, 28.1233, 17.196, 16.3555, 28.1233, 12.4344, 13.8615, 28.1233, 7.9293, 12.6312, 28.1233, 6.3504, 28.1591, 56.6813, 16.2474, 25.2804, 56.6813, 12.9911, 47.6451, 56.6813, 49.9746, 41.9222, 56.6813, 39.8854, 37.2596, 56.6813, 29.3883, 32.1493, 56.6813, 23.1624, 29.5765, 66.007, 14.7727, 47.6799, 76.3034, 35.121, 70.119, 87.6183, 69.0486, +0,0,0, 2.108, 2.9891, 2.7904, 1.6702, 2.9891, 2.3311, 3.4115, 6.2359, 5.1996, 8.8419, 11.251, 11.3399, 7.2572, 11.251, 9.8606, 6.1947, 11.251, 9.3344, 10.0632, 18.4187, 15.1057, 23.2833, 28.1233, 28.5625, 20.1319, 28.1233, 26.9643, 17.3352, 28.1233, 24.4685, 15.2558, 28.1233, 23.2349, 22.1968, 40.7494, 33.9779, 48.3497, 56.6813, 57.9764, 43.2329, 56.6813, 54.4056, 38.5515, 56.6813, 50.1932, 34.1577, 56.6813, 47.0353, 30.8994, 56.6813, 44.527, 35.9901, 66.007, 50.7477, 49.0016, 76.3034, 63.8159, 62.2486, 82.967, 76.3862, +0,0,0, 2.3453, 2.9891, 3.7174, 1.926, 2.9891, 4.4245, 4.0173, 6.2359, 9.6191, 9.4684, 11.251, 13.3777, 8.3988, 11.251, 15.2001, 7.3638, 11.251, 16.5584, 11.6981, 18.4187, 25.5249, 24.3887, 28.1233, 31.9199, 22.2844, 28.1233, 34.5849, 20.2715, 28.1233, 36.817, 18.2763, 28.1233, 37.3909, 25.4976, 40.7494, 52.8133, 50.1257, 56.6813, 64.0076, 46.5487, 56.6813, 66.0339, 43.1626, 56.6813, 68.3981, 39.8701, 56.6813, 69.2512, 35.2616, 56.6813, 70.4797, 46.08, 74.1641, 88.1726, 58.2443, 80.7044, 93.9569, 71.4332, 87.6183, 99.9575, +0,0,0, 2.4666, 2.9891, 4.4851, 2.2448, 2.9891, 5.9111, 4.6165, 6.2359, 12.0332, 9.74, 11.251, 14.9949, 8.8882, 11.251, 18.3141, 8.1128, 11.251, 21.4127, 13.2261, 18.4187, 34.5513, 24.8999, 28.1233, 35.3653, 23.1907, 28.1233, 40.724, 21.6271, 28.1233, 46.921, 19.8433, 28.1233, 50.4344, 28.2041, 40.7494, 69.0229, 50.8535, 56.6813, 68.8802, 47.8889, 56.6813, 76.2798, 44.6584, 56.6813, 82.046, 41.6195, 56.6813, 88.1993, 39.0704, 56.6813, 94.4482, 49.8666, 66.007, 100.2007, 62.9735, 76.3034, 103.0157, 78.0945, 87.6183, 105.3757, +0,0,0, 2.4364, 1.9086, 1.4688, 3.168, 1.9086, 0.9391, 5.5818, 2.9891, 1.1895, 7.265, 6.2359, 5.462, 8.7473, 6.2359, 4.1462, 10.3312, 6.2359, 2.8546, 11.6178, 6.2359, 2.127, 20.8807, 11.251, 3.7728, 20.1146, 18.4187, 16.7921, 23.0654, 18.4187, 14.2768, 26.3119, 18.4187, 12.1097, 29.4922, 18.4187, 9.1904, 33.7924, 18.4187, 5.6569, 41.9121, 22.9298, 6.3588, 52.713, 34.0472, 18.642, 43.1587, 40.7494, 39.0086, 47.8373, 40.7494, 33.728, 52.8667, 40.7494, 29.0411, 66.526, 56.6813, 45.7942, 79.0894, 76.3034, 74.2766, +0,0,0, 2.6197, 2.9891, 4.9052, 2.4789, 2.9891, 6.9067, 5.0943, 6.2359, 14.577, 10.1162, 11.251, 15.9858, 9.6673, 11.251, 20.6324, 9.2055, 11.251, 26.0341, 14.8942, 18.4187, 42.8274, 25.5352, 28.1233, 37.1142, 24.4632, 28.1233, 44.6614, 23.4074, 28.1233, 53.131, 22.2932, 28.1233, 62.3583, 31.9264, 40.7494, 92.1437, 44.1905, 48.2781, 61.8135, 42.3672, 48.2781, 71.7357, 40.7141, 48.2781, 82.9579, 39.2461, 48.2781, 95.6828, 47.2962, 56.6813, 100.3071, 57.2536, 66.007, 101.5921, 67.9355, 76.3034, 103.436, +0,0,0, 2.7982, 2.9891, 8.6685, 4.1208, 4.4155, 7.1309, 4.1612, 4.4155, 10.1433, 6.0966, 6.2359, 18.7302, 10.5606, 11.251, 16.4317, 10.4042, 11.251, 21.4695, 10.4747, 11.251, 27.5383, 10.5836, 11.251, 33.8709, 18.1547, 18.4187, 55.3577, 26.2553, 28.1233, 38.0059, 25.8303, 28.1233, 46.5439, 25.9521, 28.1233, 56.6217, 26.7324, 28.1233, 68.0523, 28.0301, 28.1233, 84.418, 33.806, 34.0472, 96.8792, 42.4315, 45.1644, 99.9617, 52.8874, 56.6813, 73.1468, 52.3387, 56.6813, 86.2998, 52.4765, 56.6813, 101.3278, 70.8398, 76.3034, 102.9002, +0,0,0, 3.0398, 2.9891, 6.1233, 3.3574, 2.9891, 10.1548, 3.7776, 2.9891, 14.0607, 8.1239, 6.2359, 28.9466, 8.3832, 8.4984, 14.7224, 8.87, 8.4984, 21.8435, 9.7338, 8.4984, 30.3378, 11.1523, 8.4984, 39.3449, 15.0163, 11.251, 50.4059, 17.9346, 18.4187, 28.9351, 18.4058, 18.4187, 40.1114, 19.842, 18.4187, 52.7573, 21.8326, 18.4187, 66.4797, 24.474, 18.4187, 83.4294, 32.3931, 28.1233, 95.1349, 32.5501, 34.0472, 50.2969, 33.1968, 34.0472, 66.2406, 35.3672, 34.0472, 83.913, 36.8082, 34.0472, 96.9789, 45.6537, 45.1644, 100.359, 53.8261, 56.6813, 80.0104, 55.3271, 56.6813, 101.2963, 72.3061, 76.3034, 105.1867, +0,0,0, 3.7048, 2.9891, 5.9648, 4.754, 2.9891, 9.7663, 6.0374, 2.9891, 14.6405, 7.3117, 2.9891, 19.7734, 15.1352, 6.2359, 42.7145, 19.0702, 8.4984, 52.0012, 9.6873, 8.4984, 14.6268, 11.4333, 8.4984, 22.0239, 13.6517, 8.4984, 30.3894, 16.1808, 8.4984, 40.3975, 27.2723, 11.251, 78.181, 34.004, 18.4187, 85.7156, 19.9887, 18.4187, 29.2578, 22.6043, 18.4187, 41.2528, 26.022, 18.4187, 53.9744, 29.6726, 18.4187, 69.3691, 42.7495, 28.1233, 95.3079, 35.8782, 34.0472, 51.104, 39.7286, 34.0472, 68.1086, 44.5219, 34.0472, 86.2127, 52.0133, 40.7494, 99.9868, 58.4479, 56.6813, 81.8948, 63.3425, 56.6813, 104.0201, 77.4496, 76.3034, 106.882, +0,0,0, 5.9792, 2.9891, 6.7983, 5.6611, 4.4155, 6.4892, 7.4487, 4.4155, 8.4184, 12.5371, 6.2359, 14.8021, 16.887, 14.5417, 19.8849, 20.5757, 14.5417, 23.2471, 24.6615, 14.5417, 27.6573, 29.0646, 14.5417, 33.9618, 37.1009, 18.4187, 44.326, 55.3607, 28.1233, 75.2024, 31.4203, 28.1233, 36.8351, 36.8426, 28.1233, 42.4991, 42.7739, 28.1233, 49.2386, 48.8039, 28.1233, 60.1262, 65.0875, 40.7494, 82.7335, 52.4811, 48.2781, 61.791, 59.8114, 48.2781, 71.3579, 67.3205, 48.2781, 84.8059, 72.5461, 56.6813, 91.3143, 82.5715, 76.3034, 98.8142, +0,0,0, 3.6781, 2.9891, 1.4811, 4.3912, 2.9891, 0.4572, 7.2096, 6.2359, 3.6436, 8.6369, 6.2359, 1.6378, 9.3726, 6.2359, 0.7023, 17.1277, 11.251, 1.2299, 15.9324, 14.5417, 9.8473, 18.4248, 14.5417, 5.7809, 20.8121, 14.5417, 2.8115, 27.2709, 18.4187, 1.7329, 30.0809, 28.1233, 21.2298, 33.7425, 28.1233, 14.0395, 37.1325, 28.1233, 8.2291, 38.9601, 28.1233, 3.5885, 40.9676, 28.1233, 2.275, 52.976, 40.7494, 11.72, 50.1955, 48.2781, 38.0164, 54.5519, 48.2781, 26.1853, 63.3032, 56.6813, 32.6901, 77.0216, 76.3034, 65.1076, +0,0,0, 3.3197, 2.9891, 1.148, 3.5138, 2.9891, 0.6227, 6.6846, 6.2359, 3.0931, 7.4603, 6.2359, 1.1325, 13.4731, 11.251, 1.8616, 14.8686, 14.5417, 8.7303, 16.3904, 14.5417, 4.3255, 21.7903, 18.4187, 2.9308, 28.5178, 28.1233, 19.2981, 30.4615, 28.1233, 11.2259, 32.3158, 28.1233, 5.7361, 33.187, 28.1233, 4.2045, 46.0119, 40.7494, 5.6175, 48.3113, 48.2781, 35.8235, 50.4509, 48.2781, 22.8894, 52.5746, 48.2781, 13.4945, 54.6262, 48.2781, 7.0769, 61.6913, 56.6813, 16.4547, 67.8322, 66.007, 33.3101, 75.4525, 76.3034, 54.1791, +0,0,0, 2.8909, 2.9891, 1.0142, 5.9861, 6.2359, 2.8395, 6.187, 6.2359, 1.0384, 10.8221, 11.251, 1.7582, 13.8453, 14.5417, 8.4043, 14.0725, 14.5417, 3.7708, 17.4718, 18.4187, 2.7642, 26.6956, 28.1233, 18.6195, 26.7106, 28.1233, 10.2615, 26.5222, 28.1233, 4.8764, 37.8172, 40.7494, 6.0499, 45.2991, 48.2781, 34.9471, 44.8363, 48.2781, 21.7887, 44.4752, 48.2781, 12.426, 51.2315, 56.6813, 8.5942, 70.9748, 76.3034, 58.9282, 70.1174, 76.3034, 39.8412, 69.8154, 76.3034, 25.3302, 70.5383, 76.3034, 14.8054, 70.4427, 76.3034, 11.249, +-1,-1,-1 +}; + + diff --git a/xicc/cam02.c b/xicc/cam02.c index db9c3259..bd996b5c 100644 --- a/xicc/cam02.c +++ b/xicc/cam02.c @@ -18,6 +18,8 @@ * Experiment within an ICC Workflow", page 215, together with * their matrix formulation of inversion has been adopted. * + * A blue hue linearization tweak is also used. + * * In addition the algorithm has unique extensions to allow * it to operate reasonably over an unbounded domain. * @@ -111,6 +113,14 @@ effects over the range of J from 0 to 100, and have more moderate effects outside this range. + To compensate for the slight CIECAM02 blue hue non-linearity at high Chroma, + a hue angle adjustment is made that is similar to that described in + the paper "Color gamut mapping in a hue-linearized CIELAB color space" + by Gustav Braun and Mark Fairchild. + + NOTE we have turned symetrical compress/decompress off (undef ENABLE_DECOMPR) + because it causes some poor gamut mapping behaviour. + */ #include @@ -123,10 +133,11 @@ #include "numlib.h" #define ENABLE_COMPR /* [Def] Enable XYZ compression */ -#undef ENABLE_DECOMPR /* [Undef] Enable XYZ de-compression */ -#define ENABLE_BLUE_ANGLE_FIX /* [Def] Limit maximum blue angle */ +#undef ENABLE_DECOMPR /* [Undef] Enable XYZ de-compression. (Will cause cam02test to fail) */ +#define ENABLE_BLUE_ANGLE_FIX /* [Def] Limit maximum blue angle to avoid numeric failure */ #define ENABLE_DDL /* [Def] Enable k1,k2,k3 overall ss limit values (seems to be the best scheme) */ #undef ENABLE_SS /* [Undef] Disable overall ss limit values (not the scheme used) */ +#define ENABLE_BLUELIN /* [Def] Enable blue linearity hack */ #undef ENTRACE /* [Undef] Enable internal value runtime tracing if s->trace != 0 */ #undef DOTRACE /* [Undef] Trace anyway (ie. set s->trace = 1) */ @@ -177,6 +188,15 @@ #define JLIMIT 0.005 /* [0.005] J encoding cutover point straight line (0 - 1.0 range) */ #define HKLIMIT 0.7 /* [0.7] Maximum Helmholtz-Kohlrausch lift out of 1.0 */ +#ifdef ENABLE_BLUELIN +#define BLUELIN_h0 210.0 /* Low limit of hue angle to tweak */ +#define BLUELIN_h1 330.0 /* High limit of hue angle at C0 to tweak */ +#define BLUELIN_C0 50.0 /* Low limit of Chroma to tweak */ +#define BLUELIN_C10 80.0 /* High end of Chroma to tweak */ +#define BLUELIN_C11 140.0 /* High end of Hue and Chroma to tweak */ +#define BLUELIN_AMNT 0.60 /* Amount to tweak hue (< 1.0 increases tweak) */ +#endif /* ENABLE_BLUELIN */ + #ifdef TRACKMINMAX double minss = 1e60; double maxss = -1e60; @@ -194,6 +214,91 @@ double minj = 1e38, maxj = -1e38; #define TRACE(xxxx) #endif +#ifdef ENABLE_BLUELIN +/* Blue hue contancy hack functions */ + +/* We are using simple linear interpolation for this. */ +static void bluelin_fwd(double out[3], double in[3]) { + double J, C, h; + + C = sqrt(in[1] * in[1] + in[2] * in[2]); + h = (180.0/DBL_PI) * atan2(in[2], in[1]); + h = (h < 0.0) ? h + 360.0 : h; + + if (h >= BLUELIN_h0 && h <= BLUELIN_h1 + && C > BLUELIN_C0) { + double hh = (h - BLUELIN_h0)/(BLUELIN_h1 - BLUELIN_h0); + double gr, c1, amnt; + + c1 = (1.0 - hh) * BLUELIN_C10 + hh * BLUELIN_C11; + + gr = (C - BLUELIN_C0)/(c1 - BLUELIN_C0); + if (gr < 0.0) + gr = 0.0; + else if (gr > 1.0) + gr = 1.0; + + amnt = (1.0 - gr) * 1.0 + gr * BLUELIN_AMNT; + + if (hh < 0.5) { + hh = hh * amnt; + } else { + hh = (0.5 * amnt) + (hh - 0.5) * (1.0 - 0.5 * amnt)/0.5; + } + + h = BLUELIN_h0 + hh * (BLUELIN_h1 - BLUELIN_h0); + } + + h = DBL_PI/180.0 * h; + out[0] = in[0]; + out[1] = C * cos(h); + out[2] = C * sin(h); +} + +static void bluelin_bwd(double out[3], double in[3]) { + double J, C, h; + + C = sqrt(in[1] * in[1] + in[2] * in[2]); + h = (180.0/DBL_PI) * atan2(in[2], in[1]); + h = (h < 0.0) ? h + 360.0 : h; + + if (h >= BLUELIN_h0 && h <= BLUELIN_h1 + && C > BLUELIN_C0) { + double hh = (h - BLUELIN_h0)/(BLUELIN_h1 - BLUELIN_h0); + double ho = hh; + double gr, c1 = 0.0, pc1 = -100.0, amnt; + int j; + + /* Should be able to compute inverse analytically, but for the moment */ + /* we'll simply itterate to sufficient accuracy... */ + for (j = 0; fabs(c1 - pc1) > 0.02 && j < 20; j++) { + pc1 = c1; + c1 = (1.0 - ho) * BLUELIN_C10 + ho * BLUELIN_C11; + + gr = (C - BLUELIN_C0)/(c1 - BLUELIN_C0); + if (gr < 0.0) + gr = 0.0; + else if (gr > 1.0) + gr = 1.0; + + amnt = (1.0 - gr) * 1.0 + gr * BLUELIN_AMNT; + + if (hh < (0.5 * amnt)) { + ho = hh / amnt; + } else { + ho = 0.5 + (hh - 0.5 * amnt) * (1.0 - 0.5)/(1.0 - 0.5 * amnt); + } + } + h = BLUELIN_h0 + ho * (BLUELIN_h1 - BLUELIN_h0); + } + + h = DBL_PI/180.0 * h; + out[0] = in[0]; + out[1] = C * cos(h); + out[2] = C * sin(h); +} +#endif /* ENABLE_BLUELIN */ + 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], @@ -211,7 +316,6 @@ static double spow(double val, double pp) { /* Create a cam02 conversion object, with default viewing conditions */ cam02 *new_cam02(void) { cam02 *s; -// double D50[3] = { 0.9642, 1.0000, 0.8249 }; if ((s = (cam02 *)calloc(1, sizeof(cam02))) == NULL) { fprintf(stderr,"cam02: malloc failed allocating object\n"); @@ -236,9 +340,10 @@ cam02 *new_cam02(void) { s->ssmincj = SSMINcJ; s->jlimit = JLIMIT; s->hklimit = 1.0 / HKLIMIT; + s->bluelin = 1; /* Default is enabled */ - /* Set a default viewing condition ?? */ - /* set_view(s, vc_average, D50, 33, 0.2, 0.0, 0.0, D50, 0); */ + /* Set a default viewing condition */ + set_view(s, vc_average, icmD50_ary3, 33, 0.2, 0.0, 0.0, 0.0, icmD50_ary3, 0, 0.0, 0.0, NULL); #ifdef DOTRACE s->trace = 1; @@ -818,6 +923,8 @@ double XYZ[3] rgbp[0] = ss * tt + (1.0 - ss) * rgbp[0]; rgbp[1] = ss * tt + (1.0 - ss) * rgbp[1]; TRACE(("rgbp after blue fix ss = %f, rgbp = %f %f %f\n",ss,rgbp[0], rgbp[1], rgbp[2])) +#else +# pragma message("!!!!!!!!!!!! ENABLE_BLUE_ANGLE_FIX os not set !!!!!!!!!") #endif #ifdef DISABLE_NONLIN @@ -1044,6 +1151,13 @@ double XYZ[3] Jab[1] = ja; Jab[2] = jb; +#ifdef ENABLE_BLUELIN + if (s->bluelin) { + TRACE(("Jab pre blin %f %f %f\n",Jab[0], Jab[1], Jab[2])) + bluelin_fwd(Jab, Jab); + } +#endif + #ifdef NEVER /* Brightness/Colorfulness */ { double M, Q; @@ -1101,6 +1215,13 @@ double Jab[3] TRACE(("\nCIECAM02 Reverse conversion:\n")) TRACE(("Jab %f %f %f\n",Jab[0], Jab[1], Jab[2])) +#ifdef ENABLE_BLUELIN + if (s->bluelin) { + bluelin_bwd(Jab, Jab); + TRACE(("blin Jab %f %f %f\n",Jab[0], Jab[1], Jab[2])) + } +#endif + JJ = Jab[0] * 0.01; /* J/100 */ ja = Jab[1]; jb = Jab[2]; @@ -1282,6 +1403,7 @@ double Jab[3] #ifdef ENABLE_DECOMPR +# pragma message("!!!!!!!!!!!! ENABLE_DECOMPR is set !!!!!!!!!") /* Undo soft limiting */ { double tt; /* Temporary */ diff --git a/xicc/cam02.h b/xicc/cam02.h index bf9d9c93..ff2cc191 100644 --- a/xicc/cam02.h +++ b/xicc/cam02.h @@ -149,7 +149,7 @@ struct _cam02 { double Wxyz2[3] /* Mid tone Adapted White XYZ (Y range 0.0 .. 1.0) */ ); - /* Conversions. Return nz on error */ + /* Conversions. Return nz on error (Y scale 1.0) */ int (*XYZ_to_cam)(struct _cam02 *s, double *out, double *in); int (*cam_to_XYZ)(struct _cam02 *s, double *out, double *in); @@ -214,6 +214,7 @@ struct _cam02 { /* Option flags, code not always enabled */ int hk; /* Use Helmholtz-Kohlrausch effect */ int hkscale; /* [1.0] Scale HK effect up/down from default */ + int bluelin; /* Use blue hue linearization */ 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/cam02test.c b/xicc/cam02test.c index 2b57b054..aacd6f9b 100644 --- a/xicc/cam02test.c +++ b/xicc/cam02test.c @@ -15,6 +15,8 @@ /* * This is some test code to test the CIECAM02 functionality. + * This isn't very useful when cam02.c has undef ENABLE_DECOMPR. + * The */ @@ -31,7 +33,7 @@ #undef DIAG /* Print internal value diagnostics for each spot test conversion */ /* and print diagnostics for excessive errors, nans etc. */ #undef VERBOSE /* Print diagnostic values for every conversion */ -#define SPOTTEST /* ** Test known spot colors */ +#undef SPOTTEST /* ** Test known spot colors */ #undef TROUBLE /* Test trouble spot colors XYZ -> Jab -> XYZ */ #undef TROUBLE2 /* Test trouble spot colors Jab -> XYZ -> Jab */ #undef SPECIAL /* Special exploration code */ @@ -50,13 +52,13 @@ //#define TRES 41 /* Grid resolution */ #define TRES 17 /* Grid resolution */ #define USE_HK 0 /* Use Helmholtz-Kohlraush in testing */ -#define EXIT_ON_ERROR /* and also trace */ +#undef EXIT_ON_ERROR /* and also trace */ //#define MAX_SPOT_ERR 0.05 //#define MAX_REF_ERR 0.1 /* Maximum permitted error to reference transform in delta Jab */ /* The blue fix throws this out */ #define MAX_SPOT_ERR 2.0 -#define MAX_REF_ERR 2.0 /* Maximum permitted error to reference transform in delta Jab */ +#define MAX_REF_ERR 3.7 /* Maximum permitted error to reference transform in delta Jab */ #ifndef _isnan #define _isnan(x) ((x) != (x)) @@ -952,6 +954,7 @@ main(void) { double jmin[3] = { 1e38, 1e38, 1e38 }; double jmax[3] = { -1e38, -1e38, -1e38 }; double merr = 0.0; + int ntests = 0; for (c = 0; c < 6; c++) { int co0, co1, co2; /* (using co[3] triggers compiler bug) */ double xyz[3], Lab[3], Jab[3], checkxyz[3]; @@ -1068,6 +1071,7 @@ main(void) { jmax[i] = Jab[i]; } cam->cam_to_XYZ(cam, checkxyz, Jab); + ntests++; /* Check the result */ mxd = maxxyzdiff(checkxyz, xyz); @@ -1107,13 +1111,13 @@ main(void) { } #endif /* INVTEST */ } - if (!_finite(merr) || merr > 0.15) { - printf("INVTEST: Excessive error in roundtrip check %f DE\n",merr); + if (!_finite(merr) || merr > 3.7) { + printf("INVTEST: Excessive error in roundtrip check %f DE (max allowd 3.7)\n",merr); ok = 0; } printf("\n"); printf("XYZ -> Jab -> XYZ\n"); - printf("Inversion check complete, peak error = %e DE\n",merr); + printf("Inversion of %d points check complete, peak error = %e DE\n",ntests, merr); printf("Range of XYZ values was:\n"); printf("X: %f -> %f\n", xmin[0], xmax[0]); printf("Y: %f -> %f\n", xmin[1], xmax[1]); @@ -1136,6 +1140,7 @@ main(void) { double jmin[3] = { 1e38, 1e38, 1e38 }; double jmax[3] = { -1e38, -1e38, -1e38 }; double merr = 0.0; + int ntests = 0; for (c = 0; c < 6; c++) { int i, j; @@ -1289,6 +1294,7 @@ main(void) { xmax[i] = xyz[i]; } cam->XYZ_to_cam(cam, checkJab, xyz); + ntests++; /* Check the result */ mxd = maxdiff(checkJab, Jab); @@ -1324,13 +1330,13 @@ main(void) { } #endif /* TESTINV */ } - if (!_finite(merr) || merr > 1.0) { - printf("TESTINV: Excessive error in roundtrip check %f\n",merr); + if (!_finite(merr) || merr > 3.7) { + printf("TESTINV: Excessive error in roundtrip check %f (max allowed 3.7)\n",merr); ok = 0; } printf("\n"); printf("Jab -> XYX -> Jab\n"); - printf("Inversion check 2 complete, peak error = %e DE Jab\n",merr); + printf("Inversion check 2 of %d points complete, peak error = %e DE Jab\n",ntests,merr); printf("Range of Jab values was:\n"); printf("J: %f -> %f\n", jmin[0], jmax[0]); printf("a: %f -> %f\n", jmin[1], jmax[1]);