diff options
Diffstat (limited to 'profile')
-rw-r--r-- | profile/F1.sp | 106 | ||||
-rw-r--r-- | profile/F5.sp | 106 | ||||
-rw-r--r-- | profile/F8.sp | 106 | ||||
-rw-r--r-- | profile/Jamfile | 6 | ||||
-rw-r--r-- | profile/afiles | 5 | ||||
-rw-r--r-- | profile/colprof.c | 96 | ||||
-rw-r--r-- | profile/colverify.c (renamed from profile/verify.c) | 401 | ||||
-rw-r--r-- | profile/prof.h | 2 | ||||
-rw-r--r-- | profile/profcheck.c | 2 | ||||
-rw-r--r-- | profile/profin.c | 9 | ||||
-rw-r--r-- | profile/profout.c | 156 | ||||
-rw-r--r-- | profile/txt2ti3.c | 6 |
12 files changed, 837 insertions, 164 deletions
diff --git a/profile/F1.sp b/profile/F1.sp new file mode 100644 index 0000000..908cd72 --- /dev/null +++ b/profile/F1.sp @@ -0,0 +1,106 @@ +SPECT + +DESCRIPTOR "Argyll F1 illimunant spectral power" + +ORIGINATOR "Argyll CMS" + +CREATED "Fri Jul 06 17:49:57 2001" +KEYWORD "SPECTRAL_BANDS" +SPECTRAL_BANDS "81" +KEYWORD "SPECTRAL_START_NM" +SPECTRAL_START_NM "380.000000" +KEYWORD "SPECTRAL_END_NM" +SPECTRAL_END_NM "780.000000" +KEYWORD "SPECTRAL_NORM" +SPECTRAL_NORM "30.00" + +KEYWORD "SPEC_380" +KEYWORD "SPEC_385" +KEYWORD "SPEC_390" +KEYWORD "SPEC_395" +KEYWORD "SPEC_400" +KEYWORD "SPEC_405" +KEYWORD "SPEC_410" +KEYWORD "SPEC_415" +KEYWORD "SPEC_420" +KEYWORD "SPEC_425" +KEYWORD "SPEC_430" +KEYWORD "SPEC_435" +KEYWORD "SPEC_440" +KEYWORD "SPEC_445" +KEYWORD "SPEC_450" +KEYWORD "SPEC_455" +KEYWORD "SPEC_460" +KEYWORD "SPEC_465" +KEYWORD "SPEC_470" +KEYWORD "SPEC_475" +KEYWORD "SPEC_480" +KEYWORD "SPEC_485" +KEYWORD "SPEC_490" +KEYWORD "SPEC_495" +KEYWORD "SPEC_500" +KEYWORD "SPEC_505" +KEYWORD "SPEC_510" +KEYWORD "SPEC_515" +KEYWORD "SPEC_520" +KEYWORD "SPEC_525" +KEYWORD "SPEC_530" +KEYWORD "SPEC_535" +KEYWORD "SPEC_540" +KEYWORD "SPEC_545" +KEYWORD "SPEC_550" +KEYWORD "SPEC_555" +KEYWORD "SPEC_560" +KEYWORD "SPEC_565" +KEYWORD "SPEC_570" +KEYWORD "SPEC_575" +KEYWORD "SPEC_580" +KEYWORD "SPEC_585" +KEYWORD "SPEC_590" +KEYWORD "SPEC_595" +KEYWORD "SPEC_600" +KEYWORD "SPEC_605" +KEYWORD "SPEC_610" +KEYWORD "SPEC_615" +KEYWORD "SPEC_620" +KEYWORD "SPEC_625" +KEYWORD "SPEC_630" +KEYWORD "SPEC_635" +KEYWORD "SPEC_640" +KEYWORD "SPEC_645" +KEYWORD "SPEC_650" +KEYWORD "SPEC_655" +KEYWORD "SPEC_660" +KEYWORD "SPEC_665" +KEYWORD "SPEC_670" +KEYWORD "SPEC_675" +KEYWORD "SPEC_680" +KEYWORD "SPEC_685" +KEYWORD "SPEC_690" +KEYWORD "SPEC_695" +KEYWORD "SPEC_700" +KEYWORD "SPEC_705" +KEYWORD "SPEC_710" +KEYWORD "SPEC_715" +KEYWORD "SPEC_720" +KEYWORD "SPEC_725" +KEYWORD "SPEC_730" +KEYWORD "SPEC_735" +KEYWORD "SPEC_740" +KEYWORD "SPEC_745" +KEYWORD "SPEC_750" +KEYWORD "SPEC_755" +KEYWORD "SPEC_760" +KEYWORD "SPEC_765" +KEYWORD "SPEC_770" +KEYWORD "SPEC_775" +KEYWORD "SPEC_780" +NUMBER_OF_FIELDS 81 +BEGIN_DATA_FORMAT +SPEC_380 SPEC_385 SPEC_390 SPEC_395 SPEC_400 SPEC_405 SPEC_410 SPEC_415 SPEC_420 SPEC_425 SPEC_430 SPEC_435 SPEC_440 SPEC_445 SPEC_450 SPEC_455 SPEC_460 SPEC_465 SPEC_470 SPEC_475 SPEC_480 SPEC_485 SPEC_490 SPEC_495 SPEC_500 SPEC_505 SPEC_510 SPEC_515 SPEC_520 SPEC_525 SPEC_530 SPEC_535 SPEC_540 SPEC_545 SPEC_550 SPEC_555 SPEC_560 SPEC_565 SPEC_570 SPEC_575 SPEC_580 SPEC_585 SPEC_590 SPEC_595 SPEC_600 SPEC_605 SPEC_610 SPEC_615 SPEC_620 SPEC_625 SPEC_630 SPEC_635 SPEC_640 SPEC_645 SPEC_650 SPEC_655 SPEC_660 SPEC_665 SPEC_670 SPEC_675 SPEC_680 SPEC_685 SPEC_690 SPEC_695 SPEC_700 SPEC_705 SPEC_710 SPEC_715 SPEC_720 SPEC_725 SPEC_730 SPEC_735 SPEC_740 SPEC_745 SPEC_750 SPEC_755 SPEC_760 SPEC_765 SPEC_770 SPEC_775 SPEC_780 +END_DATA_FORMAT + +NUMBER_OF_SETS 1 +BEGIN_DATA +1.87 2.36 2.94 3.47 5.17 19.49 6.13 6.24 7.01 7.79 8.56 43.67 16.94 10.72 11.35 11.89 12.37 12.75 13.00 13.15 13.23 13.17 13.13 12.85 12.52 12.20 11.83 11.50 11.22 11.05 11.03 11.18 11.53 27.74 17.05 13.55 14.33 15.01 15.52 18.29 19.55 15.48 14.91 14.15 13.22 12.19 11.12 10.03 8.95 7.96 7.02 6.20 5.42 4.73 4.15 3.64 3.20 2.81 2.47 2.18 1.93 1.72 1.67 1.43 1.29 1.19 1.08 0.96 0.88 0.81 0.77 0.75 0.73 0.68 0.69 0.64 0.68 0.69 0.61 0.52 0.43 +END_DATA diff --git a/profile/F5.sp b/profile/F5.sp new file mode 100644 index 0000000..4959a50 --- /dev/null +++ b/profile/F5.sp @@ -0,0 +1,106 @@ +SPECT + +DESCRIPTOR "Argyll F5 illimunant spectral power" + +ORIGINATOR "Argyll CMS" + +CREATED "Fri Jul 06 17:49:57 2001" +KEYWORD "SPECTRAL_BANDS" +SPECTRAL_BANDS "81" +KEYWORD "SPECTRAL_START_NM" +SPECTRAL_START_NM "380.000000" +KEYWORD "SPECTRAL_END_NM" +SPECTRAL_END_NM "780.000000" +KEYWORD "SPECTRAL_NORM" +SPECTRAL_NORM "30.00" + +KEYWORD "SPEC_380" +KEYWORD "SPEC_385" +KEYWORD "SPEC_390" +KEYWORD "SPEC_395" +KEYWORD "SPEC_400" +KEYWORD "SPEC_405" +KEYWORD "SPEC_410" +KEYWORD "SPEC_415" +KEYWORD "SPEC_420" +KEYWORD "SPEC_425" +KEYWORD "SPEC_430" +KEYWORD "SPEC_435" +KEYWORD "SPEC_440" +KEYWORD "SPEC_445" +KEYWORD "SPEC_450" +KEYWORD "SPEC_455" +KEYWORD "SPEC_460" +KEYWORD "SPEC_465" +KEYWORD "SPEC_470" +KEYWORD "SPEC_475" +KEYWORD "SPEC_480" +KEYWORD "SPEC_485" +KEYWORD "SPEC_490" +KEYWORD "SPEC_495" +KEYWORD "SPEC_500" +KEYWORD "SPEC_505" +KEYWORD "SPEC_510" +KEYWORD "SPEC_515" +KEYWORD "SPEC_520" +KEYWORD "SPEC_525" +KEYWORD "SPEC_530" +KEYWORD "SPEC_535" +KEYWORD "SPEC_540" +KEYWORD "SPEC_545" +KEYWORD "SPEC_550" +KEYWORD "SPEC_555" +KEYWORD "SPEC_560" +KEYWORD "SPEC_565" +KEYWORD "SPEC_570" +KEYWORD "SPEC_575" +KEYWORD "SPEC_580" +KEYWORD "SPEC_585" +KEYWORD "SPEC_590" +KEYWORD "SPEC_595" +KEYWORD "SPEC_600" +KEYWORD "SPEC_605" +KEYWORD "SPEC_610" +KEYWORD "SPEC_615" +KEYWORD "SPEC_620" +KEYWORD "SPEC_625" +KEYWORD "SPEC_630" +KEYWORD "SPEC_635" +KEYWORD "SPEC_640" +KEYWORD "SPEC_645" +KEYWORD "SPEC_650" +KEYWORD "SPEC_655" +KEYWORD "SPEC_660" +KEYWORD "SPEC_665" +KEYWORD "SPEC_670" +KEYWORD "SPEC_675" +KEYWORD "SPEC_680" +KEYWORD "SPEC_685" +KEYWORD "SPEC_690" +KEYWORD "SPEC_695" +KEYWORD "SPEC_700" +KEYWORD "SPEC_705" +KEYWORD "SPEC_710" +KEYWORD "SPEC_715" +KEYWORD "SPEC_720" +KEYWORD "SPEC_725" +KEYWORD "SPEC_730" +KEYWORD "SPEC_735" +KEYWORD "SPEC_740" +KEYWORD "SPEC_745" +KEYWORD "SPEC_750" +KEYWORD "SPEC_755" +KEYWORD "SPEC_760" +KEYWORD "SPEC_765" +KEYWORD "SPEC_770" +KEYWORD "SPEC_775" +KEYWORD "SPEC_780" +NUMBER_OF_FIELDS 81 +BEGIN_DATA_FORMAT +SPEC_380 SPEC_385 SPEC_390 SPEC_395 SPEC_400 SPEC_405 SPEC_410 SPEC_415 SPEC_420 SPEC_425 SPEC_430 SPEC_435 SPEC_440 SPEC_445 SPEC_450 SPEC_455 SPEC_460 SPEC_465 SPEC_470 SPEC_475 SPEC_480 SPEC_485 SPEC_490 SPEC_495 SPEC_500 SPEC_505 SPEC_510 SPEC_515 SPEC_520 SPEC_525 SPEC_530 SPEC_535 SPEC_540 SPEC_545 SPEC_550 SPEC_555 SPEC_560 SPEC_565 SPEC_570 SPEC_575 SPEC_580 SPEC_585 SPEC_590 SPEC_595 SPEC_600 SPEC_605 SPEC_610 SPEC_615 SPEC_620 SPEC_625 SPEC_630 SPEC_635 SPEC_640 SPEC_645 SPEC_650 SPEC_655 SPEC_660 SPEC_665 SPEC_670 SPEC_675 SPEC_680 SPEC_685 SPEC_690 SPEC_695 SPEC_700 SPEC_705 SPEC_710 SPEC_715 SPEC_720 SPEC_725 SPEC_730 SPEC_735 SPEC_740 SPEC_745 SPEC_750 SPEC_755 SPEC_760 SPEC_765 SPEC_770 SPEC_775 SPEC_780 +END_DATA_FORMAT + +NUMBER_OF_SETS 1 +BEGIN_DATA +1.87 2.35 2.92 3.45 5.10 18.91 6.00 6.11 6.85 7.58 8.31 40.76 16.06 10.32 10.91 11.40 11.83 12.17 12.40 12.54 12.58 12.52 12.47 12.20 11.89 11.61 11.33 11.10 10.96 10.97 11.16 11.54 12.12 27.78 17.73 14.47 15.20 15.77 16.10 18.54 19.50 15.39 14.64 13.72 12.69 11.57 10.45 9.35 8.29 7.32 6.41 5.63 4.90 4.26 3.72 3.25 2.83 2.49 2.19 1.93 1.71 1.52 1.43 1.26 1.13 1.05 0.96 0.85 0.78 0.72 0.68 0.67 0.65 0.61 0.62 0.59 0.62 0.64 0.55 0.47 0.40 +END_DATA diff --git a/profile/F8.sp b/profile/F8.sp new file mode 100644 index 0000000..f1e7beb --- /dev/null +++ b/profile/F8.sp @@ -0,0 +1,106 @@ +SPECT + +DESCRIPTOR "Argyll F8 illimunant spectral power" + +ORIGINATOR "Argyll CMS" + +CREATED "Fri Jul 06 17:49:57 2001" +KEYWORD "SPECTRAL_BANDS" +SPECTRAL_BANDS "81" +KEYWORD "SPECTRAL_START_NM" +SPECTRAL_START_NM "380.000000" +KEYWORD "SPECTRAL_END_NM" +SPECTRAL_END_NM "780.000000" +KEYWORD "SPECTRAL_NORM" +SPECTRAL_NORM "30.00" + +KEYWORD "SPEC_380" +KEYWORD "SPEC_385" +KEYWORD "SPEC_390" +KEYWORD "SPEC_395" +KEYWORD "SPEC_400" +KEYWORD "SPEC_405" +KEYWORD "SPEC_410" +KEYWORD "SPEC_415" +KEYWORD "SPEC_420" +KEYWORD "SPEC_425" +KEYWORD "SPEC_430" +KEYWORD "SPEC_435" +KEYWORD "SPEC_440" +KEYWORD "SPEC_445" +KEYWORD "SPEC_450" +KEYWORD "SPEC_455" +KEYWORD "SPEC_460" +KEYWORD "SPEC_465" +KEYWORD "SPEC_470" +KEYWORD "SPEC_475" +KEYWORD "SPEC_480" +KEYWORD "SPEC_485" +KEYWORD "SPEC_490" +KEYWORD "SPEC_495" +KEYWORD "SPEC_500" +KEYWORD "SPEC_505" +KEYWORD "SPEC_510" +KEYWORD "SPEC_515" +KEYWORD "SPEC_520" +KEYWORD "SPEC_525" +KEYWORD "SPEC_530" +KEYWORD "SPEC_535" +KEYWORD "SPEC_540" +KEYWORD "SPEC_545" +KEYWORD "SPEC_550" +KEYWORD "SPEC_555" +KEYWORD "SPEC_560" +KEYWORD "SPEC_565" +KEYWORD "SPEC_570" +KEYWORD "SPEC_575" +KEYWORD "SPEC_580" +KEYWORD "SPEC_585" +KEYWORD "SPEC_590" +KEYWORD "SPEC_595" +KEYWORD "SPEC_600" +KEYWORD "SPEC_605" +KEYWORD "SPEC_610" +KEYWORD "SPEC_615" +KEYWORD "SPEC_620" +KEYWORD "SPEC_625" +KEYWORD "SPEC_630" +KEYWORD "SPEC_635" +KEYWORD "SPEC_640" +KEYWORD "SPEC_645" +KEYWORD "SPEC_650" +KEYWORD "SPEC_655" +KEYWORD "SPEC_660" +KEYWORD "SPEC_665" +KEYWORD "SPEC_670" +KEYWORD "SPEC_675" +KEYWORD "SPEC_680" +KEYWORD "SPEC_685" +KEYWORD "SPEC_690" +KEYWORD "SPEC_695" +KEYWORD "SPEC_700" +KEYWORD "SPEC_705" +KEYWORD "SPEC_710" +KEYWORD "SPEC_715" +KEYWORD "SPEC_720" +KEYWORD "SPEC_725" +KEYWORD "SPEC_730" +KEYWORD "SPEC_735" +KEYWORD "SPEC_740" +KEYWORD "SPEC_745" +KEYWORD "SPEC_750" +KEYWORD "SPEC_755" +KEYWORD "SPEC_760" +KEYWORD "SPEC_765" +KEYWORD "SPEC_770" +KEYWORD "SPEC_775" +KEYWORD "SPEC_780" +NUMBER_OF_FIELDS 81 +BEGIN_DATA_FORMAT +SPEC_380 SPEC_385 SPEC_390 SPEC_395 SPEC_400 SPEC_405 SPEC_410 SPEC_415 SPEC_420 SPEC_425 SPEC_430 SPEC_435 SPEC_440 SPEC_445 SPEC_450 SPEC_455 SPEC_460 SPEC_465 SPEC_470 SPEC_475 SPEC_480 SPEC_485 SPEC_490 SPEC_495 SPEC_500 SPEC_505 SPEC_510 SPEC_515 SPEC_520 SPEC_525 SPEC_530 SPEC_535 SPEC_540 SPEC_545 SPEC_550 SPEC_555 SPEC_560 SPEC_565 SPEC_570 SPEC_575 SPEC_580 SPEC_585 SPEC_590 SPEC_595 SPEC_600 SPEC_605 SPEC_610 SPEC_615 SPEC_620 SPEC_625 SPEC_630 SPEC_635 SPEC_640 SPEC_645 SPEC_650 SPEC_655 SPEC_660 SPEC_665 SPEC_670 SPEC_675 SPEC_680 SPEC_685 SPEC_690 SPEC_695 SPEC_700 SPEC_705 SPEC_710 SPEC_715 SPEC_720 SPEC_725 SPEC_730 SPEC_735 SPEC_740 SPEC_745 SPEC_750 SPEC_755 SPEC_760 SPEC_765 SPEC_770 SPEC_775 SPEC_780 +END_DATA_FORMAT + +NUMBER_OF_SETS 1 +BEGIN_DATA +1.21 1.50 1.81 2.13 3.17 13.08 3.83 3.45 3.86 4.42 5.09 34.10 12.42 7.68 8.60 9.46 10.24 10.84 11.33 11.71 11.98 12.17 12.28 12.32 12.35 12.44 12.55 12.68 12.77 12.72 12.60 12.43 12.22 28.96 16.51 11.79 11.76 11.77 11.84 14.61 16.11 12.34 12.53 12.72 12.92 13.12 13.34 13.61 13.87 14.07 14.20 14.16 14.13 14.34 14.50 14.46 14.00 12.58 10.99 9.98 9.22 8.62 8.07 7.39 6.71 6.16 5.63 5.03 4.46 4.02 3.66 3.36 3.09 2.85 2.65 2.51 2.37 2.15 1.89 1.61 1.32 +END_DATA diff --git a/profile/Jamfile b/profile/Jamfile index 780f9a5..5c286b9 100644 --- a/profile/Jamfile +++ b/profile/Jamfile @@ -7,11 +7,11 @@ PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; #Products Libraries = libprof ; Executables = cb2ti3 kodak2ti3 txt2ti3 splitti3 mppcheck mppprof - profcheck invprofcheck verify colprof printcal applycal ; + profcheck invprofcheck colverify colprof printcal applycal ; Headers = prof.h ; Samples = example.sp example121.sp 3dap5k.sp GTIPlus.sp Office.sp Trulux.sp TruluxPlus.sp D50_0.0.sp D50_0.1.sp D50_0.3.sp D50_0.5.sp D50_0.7.sp D50_1.0.sp D50_1.2.sp - D50_1.5.sp D50_1.7.sp D50_2.0.sp D50_2.5.sp D50_3.0.sp CIE_C.sp ; + D50_1.5.sp D50_1.7.sp D50_2.0.sp D50_2.5.sp D50_3.0.sp CIE_C.sp F1.sp F5.sp F8.sp ; #Install InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ; @@ -63,7 +63,7 @@ Main mppcheck : mppcheck.c ; LINKLIBS = ../plot/libvrml $(LINKLIBS) ; # Verifyer -Main verify : verify.c ; +Main colverify : colverify.c ; LINKLIBS = libprof ../gamut/libgammap $(LINKLIBS) $(TIFFLIB) $(JPEGLIB) ; diff --git a/profile/afiles b/profile/afiles index 986bf70..8b3b980 100644 --- a/profile/afiles +++ b/profile/afiles @@ -9,7 +9,7 @@ profout.c colprof.c profcheck.c invprofcheck.c -verify.c +colverify.c applycal.c mppprof.c mppcheck.c @@ -25,6 +25,9 @@ Trulux.sp TruluxPlus.sp example.sp example121.sp +F1.sp +F5.sp +F8.sp CIE_C.sp D50_0.0.sp D50_0.1.sp diff --git a/profile/colprof.c b/profile/colprof.c index 99e02cf..b80f13c 100644 --- a/profile/colprof.c +++ b/profile/colprof.c @@ -59,13 +59,15 @@ #define DEFAVGDEV 0.5 /* Default average deviation percentage */ /* This equates to a uniform added error of +/- 1% */ +#define DEMPH_DEFAULT 1.0 /* Default dark region emphasis == none */ + /* Flags used: ABCDEFGHIJKLMNOPQRSTUVWXYZ upper . .. . ... .. .... . - lower .... .. . .. ......... . + lower .... .. . .. ......... */ @@ -94,7 +96,6 @@ void usage(char *diag, ...) { // fprintf(stderr," -q fmsu Speed - Fast, Medium (def), Slow, Ultra Slow\n"); fprintf(stderr," -b [lmhun] Low quality B2A table - or specific B2A quality or none for input device\n"); // fprintf(stderr," -b [fmsun] B2A Speed - Fast, Medium, Slow, Ultra Slow, None, same as -q (def)\n"); - fprintf(stderr," -y Verify A2B profile\n"); fprintf(stderr," -ni Don't create input (Device) shaper curves\n"); fprintf(stderr," -np Don't create input (Device) grid position curves\n"); fprintf(stderr," -no Don't create output (PCS) shaper curves\n"); @@ -121,6 +122,7 @@ void usage(char *diag, ...) { fprintf(stderr," -uc If input profile, clip cLUT values above WP\n"); fprintf(stderr," -U scale If input profile, scale media white point by scale\n"); fprintf(stderr," -R Restrict white <= 1.0, black and primaries to be +ve\n"); + fprintf(stderr," -V demphasis Degree of dark region cLUT grid emphasis 1.0-4.0 (default %.2f = none)\n",DEMPH_DEFAULT); fprintf(stderr," -f [illum] Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:\n"); fprintf(stderr," M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n"); fprintf(stderr," -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n"); @@ -172,7 +174,7 @@ int main(int argc, char *argv[]) { int verb = 0; int iquality = 1; /* A2B quality */ int oquality = -1; /* B2A quality same as A2B */ - int verify = 0; + int verify = 0; /* Not used anymore */ int noisluts = 0; /* No input shaper luts */ int noipluts = 0; /* No input position luts */ int nooluts = 0; /* No output shaper luts */ @@ -183,6 +185,7 @@ int main(int argc, char *argv[]) { int autowpsc = 0; /* Auto scale the WP to prevent clipping above WP patch */ int clipovwp = 0; /* Clip cLUT values above WP */ int clipprims = 0; /* Clip white, black and primaries */ + double demph = 0.0; /* Emphasise dark region grid resolution in cLUT */ double iwpscale = -1.0; /* Input white point scale factor */ int doinextrap = 1; /* Sythesize extra sample points for input device cLUT */ int doinb2a = 1; /* Create an input device B2A table */ @@ -238,7 +241,8 @@ int main(int argc, char *argv[]) { ivc_p.Yb = -1.0; ivc_p.Lv = -1.0; ivc_p.Yf = -1.0; - ivc_p.Fxyz[0] = -1.0; ivc_p.Fxyz[1] = -1.0; ivc_p.Fxyz[2] = -1.0; + ivc_p.Yg = -1.0; + ivc_p.Gxyz[0] = -1.0; ivc_p.Gxyz[1] = -1.0; ivc_p.Gxyz[2] = -1.0; ovc_p.Ev = -1; ovc_p.Wxyz[0] = -1.0; ovc_p.Wxyz[1] = -1.0; ovc_p.Wxyz[2] = -1.0; @@ -246,7 +250,8 @@ int main(int argc, char *argv[]) { ovc_p.Yb = -1.0; ovc_p.Lv = -1.0; ovc_p.Yf = -1.0; - ovc_p.Fxyz[0] = -1.0; ovc_p.Fxyz[1] = -1.0; ovc_p.Fxyz[2] = -1.0; + ovc_p.Yg = -1.0; + ovc_p.Gxyz[0] = -1.0; ovc_p.Gxyz[1] = -1.0; ovc_p.Gxyz[2] = -1.0; xicc_enum_gmapintent(&pgmi, icxPerceptualGMIntent, NULL); xicc_enum_gmapintent(&sgmi, icxSaturationGMIntent, NULL); @@ -276,7 +281,7 @@ int main(int argc, char *argv[]) { if (argv[fa][1] == '?') usage("Usage requested"); - else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') + else if (argv[fa][1] == 'v') verb = 1; /* Manufacturer description string */ @@ -361,7 +366,7 @@ int main(int argc, char *argv[]) { } /* Quality */ - else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') { + else if (argv[fa][1] == 'q') { fa = nfa; // if (na == NULL) usage("Expect argument to quality flag -q"); if (na == NULL) usage("Expect argument to speed flag -q"); @@ -428,11 +433,8 @@ int main(int argc, char *argv[]) { doinb2a = 0; } - else if (argv[fa][1] == 'y' || argv[fa][1] == 'Y') - verify = 1; - /* Disable input or output luts */ - else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') { + else if (argv[fa][1] == 'n') { fa = nfa; if (na == NULL) { /* Backwards compatible */ nooluts = 1; @@ -468,7 +470,7 @@ int main(int argc, char *argv[]) { fa = nfa; if (na == NULL) usage("Expected argument to input white point scale flag -U"); iwpscale = atof(na); - if (iwpscale < 0.0 || iwpscale > 100.0) + if (iwpscale < 0.0 || iwpscale > 200.0) usage("Argument '%s' to flag -U out of range",na); } /* Clip primaries */ @@ -476,8 +478,18 @@ int main(int argc, char *argv[]) { clipprims = 1; } + /* Degree of dark region emphasis */ + else if (argv[fa][1] == 'V') { + if (na == NULL) usage(0,"Expected argument to dark emphasis flag -V"); + demph = atof(na); + if (demph < 1.0 || demph > 3.0) + usage("Dark weighting argument %f to '-V' is out of range",demph); + fa = nfa; + } + /* Inking rule */ - else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') { + else if (argv[fa][1] == 'k' + || argv[fa][1] == 'K') { fa = nfa; if (na == NULL) usage("Expect argument to inking flag -k"); if (argv[fa][1] == 'k') @@ -544,7 +556,7 @@ int main(int argc, char *argv[]) { } /* Algorithm type */ - else if (argv[fa][1] == 'a' || argv[fa][1] == 'A') { + else if (argv[fa][1] == 'a') { fa = nfa; if (na == NULL) usage("Expect argument to algorithm flag -a"); switch (na[0]) { @@ -713,7 +725,8 @@ int main(int argc, char *argv[]) { } /* Percetual Source Gamut and Perceptual/Saturation Gamut Maping mode enable */ - else if (argv[fa][1] == 's' || argv[fa][1] == 'S') { + else if (argv[fa][1] == 's' + || argv[fa][1] == 'S') { if (argv[fa][1] == 'S') sepsat = 1; if (na == NULL) @@ -724,7 +737,7 @@ int main(int argc, char *argv[]) { } /* Source image gamut */ - else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') { + else if (argv[fa][1] == 'g') { if (na == NULL) usage("Unrecognised argument to source image gamut flag -g",argv[fa][1]); fa = nfa; @@ -771,7 +784,8 @@ int main(int argc, char *argv[]) { } /* Viewing conditions */ - else if (argv[fa][1] == 'c' || argv[fa][1] == 'd') { + else if (argv[fa][1] == 'c' + || argv[fa][1] == 'd') { icxViewCond *vc; if (argv[fa][1] == 'c') { @@ -781,7 +795,7 @@ int main(int argc, char *argv[]) { } fa = nfa; - if (na == NULL) usage("Viewing conditions flag (-c) needs an argument"); + if (na == NULL) usage("Viewing conditions flag (-%c) needs an argument",argv[fa][1]); if (na[1] != ':') { if (vc == &ivc_p) { if ((ivc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999) @@ -792,7 +806,7 @@ int main(int argc, char *argv[]) { } } else if (na[0] == 's' || na[0] == 'S') { if (na[1] != ':') - usage("Viewing conditions (-cs) missing ':'"); + usage("Viewing conditions (-%cs) missing ':'",argv[fa][1]); if (na[2] == 'n' || na[2] == 'N') { vc->Ev = vc_none; /* Automatic */ } else if (na[2] == 'a' || na[2] == 'A') { @@ -804,7 +818,7 @@ int main(int argc, char *argv[]) { } else if (na[2] == 'c' || na[2] == 'C') { vc->Ev = vc_cut_sheet; } else - usage("Viewing condition (-c) unrecognised surround '%c'",na[2]); + usage("Viewing condition (-%c) unrecognised surround '%c'",argv[fa][1],na[2]); } else if (na[0] == 'w' || na[0] == 'W') { double x, y, z; if (sscanf(na+1,":%lf:%lf:%lf",&x,&y,&z) == 3) { @@ -812,31 +826,35 @@ int main(int argc, char *argv[]) { } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) { vc->Wxyz[0] = x; vc->Wxyz[1] = y; } else - usage("Viewing condition (-cw) unrecognised white point '%s'",na+1); + usage("Viewing condition (-%cw) unrecognised white point '%s'",argv[fa][1],na+1); } else if (na[0] == 'a' || na[0] == 'A') { if (na[1] != ':') - usage("Viewing conditions (-ca) missing ':'"); + usage("Viewing conditions (-%ca) missing ':'",argv[fa][1]); vc->La = atof(na+2); } else if (na[0] == 'b' || na[0] == 'B') { if (na[1] != ':') - usage("Viewing conditions (-cb) missing ':'"); + usage("Viewing conditions (-%cb) missing ':'",argv[fa][1]); vc->Yb = atof(na+2)/100.0; } else if (na[0] == 'l' || na[0] == 'L') { if (na[1] != ':') - usage("Viewing conditions (-[cd]l) missing ':'"); + usage("Viewing conditions (-%cl) missing ':'",argv[fa][1]); vc->Lv = atof(na+2); } else if (na[0] == 'f' || na[0] == 'F') { + if (na[1] != ':') + usage("Viewing conditions (-%cf) missing ':'",argv[fa][1]); + vc->Yf = atof(na+2); + } else if (na[0] == 'g' || na[0] == 'G') { double x, y, z; if (sscanf(na+1,":%lf:%lf:%lf",&x,&y,&z) == 3) { - vc->Fxyz[0] = x; vc->Fxyz[1] = y; vc->Fxyz[2] = z; + vc->Gxyz[0] = x; vc->Gxyz[1] = y; vc->Gxyz[2] = z; } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) { - vc->Fxyz[0] = x; vc->Fxyz[1] = y; + vc->Gxyz[0] = x; vc->Gxyz[1] = y; } else if (sscanf(na+1,":%lf",&x) == 1) { - vc->Yf = x/100.0; + vc->Yg = x/100.0; } else - usage("Viewing condition (-cf) unrecognised flare '%s'",na+1); + usage("Viewing condition (-%cg) unrecognised flare '%s'",argv[fa][1],na+1); } else - usage("Viewing condition (-c) unrecognised sub flag '%c'",na[0]); + usage("Viewing condition (-%c) unrecognised sub flag '%c'",argv[fa][1],na[0]); } /* Gammut mapping diagnostic plots */ @@ -929,6 +947,18 @@ int main(int argc, char *argv[]) { error ("Requested spectral interpretation when data not available"); } + /* If not set in arguments, set default demph from .ti1 or default none */ + if (demph == 0.0) { + if ((ti = icg->find_kword(icg, 0, "DARK_REGION_EMPHASIS")) >= 0) { + demph = atof(icg->t[0].kdata[ti]); + demph = pow(demph, 0.7); /* Reduce intensity */ + if (verb) + printf("Dark emphasis factor %f from targen\n",demph); + } else { + demph = DEMPH_DEFAULT; + } + } + /* read the device class, and call function to create profile. */ if ((ti = icg->find_kword(icg, 0, "DEVICE_CLASS")) < 0) error ("Input file doesn't contain keyword DEVICE_CLASS"); @@ -1045,9 +1075,9 @@ int main(int argc, char *argv[]) { make_output_icc(ptype, 0, iccver, verb, iquality, oquality, noisluts, noipluts, nooluts, nocied, noptop, nostos, - gamdiag, verify, clipprims, &ink, inname, outname, icg, + gamdiag, verify, clipprims, iwpscale, &ink, inname, outname, icg, spec, tillum, &cust_tillum, illum, &cust_illum, observ, fwacomp, - smooth, avgdev, + smooth, avgdev, 1.0, ipname[0] != '\000' ? ipname : NULL, sgname[0] != '\000' ? sgname : NULL, absnames, @@ -1083,9 +1113,9 @@ int main(int argc, char *argv[]) { /* If a source gamut is provided for a Display, then a V2.4.0 profile will be created */ make_output_icc(ptype, mtxtoo, iccver, verb, iquality, oquality, noisluts, noipluts, nooluts, nocied, noptop, nostos, - gamdiag, verify, clipprims, NULL, inname, outname, icg, + gamdiag, verify, clipprims, iwpscale, NULL, inname, outname, icg, spec, icxIT_none, NULL, illum, &cust_illum, observ, 0, - smooth, avgdev, + smooth, avgdev, demph, ipname[0] != '\000' ? ipname : NULL, sgname[0] != '\000' ? sgname : NULL, absnames, diff --git a/profile/verify.c b/profile/colverify.c index 849d7fc..ba09366 100644 --- a/profile/verify.c +++ b/profile/colverify.c @@ -46,9 +46,10 @@ usage(void) { fprintf(stderr,"Verify CIE values, Version %s\n",ARGYLL_VERSION_STR); fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n"); fprintf(stderr,"usage: verify [-options] target.ti3 measured.ti3\n"); - fprintf(stderr," -v Verbose - print each patch value\n"); - fprintf(stderr," -n Normalise each files reading to white Y\n"); - fprintf(stderr," -N Normalise each files reading to white XYZ\n"); + fprintf(stderr," -v [n] Verbose mode, n >= 2 print each value\n"); + fprintf(stderr," -n Normalise each files reading to its white Y\n"); + fprintf(stderr," -N Normalise each files reading to its white XYZ\n"); + fprintf(stderr," -m Normalise each files reading to its white X+Y+Z\n"); fprintf(stderr," -D Use D50 100.0 as L*a*b* white reference\n"); fprintf(stderr," -c Show CIE94 delta E values\n"); fprintf(stderr," -k Show CIEDE2000 delta E values\n"); @@ -62,6 +63,7 @@ usage(void) { fprintf(stderr," A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n"); fprintf(stderr," -o observ Choose CIE Observer for spectral data:\n"); fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n"); + fprintf(stderr," -L profile.%s Skip any first file out of profile gamut patches\n",ICC_FILE_EXT_ND); fprintf(stderr," -X file.ccmx Apply Colorimeter Correction Matrix to second file\n"); fprintf(stderr," target.ti3 Target (reference) PCS or spectral values.\n"); fprintf(stderr," measured.ti3 Measured (actual) PCS or spectral values\n"); @@ -71,16 +73,22 @@ usage(void) { /* Patch value type */ typedef struct { char sid[50]; /* sample id */ + char loc[100]; /* sample location (empty if none) */ + int og; /* Out of gamut flag */ + double xyz[3]; /* XYZ value */ double v[3]; /* Lab value */ double de; /* Delta E */ + double ixde[3]; /* XYZ Component DE */ + double ide[3]; /* Lab Component DE */ } pval; int main(int argc, char *argv[]) { - int fa,nfa; /* current argument we're looking at */ - int verb = 0; - int norm = 0; /* 1 = norm to Y, 2 = norm to XYZ */ - int usestdd50 = 0; /* Use standard D50 instead of scaled D50 as Lab reference */ + int fa,nfa,mfa; /* current argument we're looking at */ + int verb = 0; /* Verbose level */ + int norm = 0; /* 1 = norm to White Y, 2 = norm to White XYZ */ + /* 3 = norm to White X+Y+Z */ + int usestdd50 = 0; /* Use standard D50 instead of avg white as reference */ int cie94 = 0; int cie2k = 0; int dovrml = 0; @@ -88,12 +96,20 @@ int main(int argc, char *argv[]) int dosort = 0; char ccmxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction Matrix name */ ccmx *cmx = NULL; /* Colorimeter Correction Matrix */ + char gprofname[MAXNAMEL+1] = "\000"; /* Gamut limit profile name */ + icmFile *fp = NULL; + icc *icco = NULL; + xicc *xicco = NULL; + icxLuBase *luo = NULL; struct { char name[MAXNAMEL+1]; /* Patch filename */ int isdisp; /* nz if display */ int isdnormed; /* Has display data been normalised to 100 ? */ int npat; /* Number of patches */ + int nig; /* Number of patches in gamut */ + double w[3]; /* XYZ of "white" */ + double nw[3]; /* Normalised XYZ of "white" */ pval *pat; /* patch values */ } cg[2]; /* Target and current patch file information */ @@ -123,6 +139,7 @@ int main(int argc, char *argv[]) usage(); /* Process the arguments */ + mfa = 2; /* Minimum final arguments */ for(fa = 1;fa < argc;fa++) { nfa = fa; /* skip to nfa if next argument is used */ @@ -132,7 +149,7 @@ int main(int argc, char *argv[]) if (argv[fa][2] != '\000') na = &argv[fa][2]; /* next is directly after flag */ else { - if ((fa+1) < argc) { + if ((fa+1+mfa) < argc) { if (argv[fa+1][0] != '-') { nfa = fa + 1; na = argv[nfa]; /* next is seperate non-flag argument */ @@ -143,16 +160,28 @@ int main(int argc, char *argv[]) if (argv[fa][1] == '?') usage(); - else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') + /* Verbose */ + else if (argv[fa][1] == 'v') { verb = 1; + if (na != NULL && na[0] >= '0' && na[0] <= '9') { + verb = atoi(na); + fa = nfa; + } + } + /* normalize */ - else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') { + else if (argv[fa][1] == 'n' + || argv[fa][1] == 'N') { norm = 1; if (argv[fa][1] == 'N') norm = 2; } + else if (argv[fa][1] == 'm') { + norm = 3; + } + else if (argv[fa][1] == 'D') usestdd50 = 1; @@ -167,18 +196,18 @@ int main(int argc, char *argv[]) doaxes = 1; /* CIE94 delta E */ - else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') { + else if (argv[fa][1] == 'c') { cie94 = 1; cie2k = 0; } - else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') { + else if (argv[fa][1] == 'k') { cie94 = 0; cie2k = 1; } /* Sort */ - else if (argv[fa][1] == 's' || argv[fa][1] == 'S') + else if (argv[fa][1] == 's') dosort = 1; /* FWA compensation */ @@ -224,7 +253,7 @@ int main(int argc, char *argv[]) } /* Spectral to CIE Illuminant type */ - else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') { + else if (argv[fa][1] == 'i') { fa = nfa; if (na == NULL) usage(); if (strcmp(na, "A") == 0) { @@ -260,7 +289,7 @@ int main(int argc, char *argv[]) } /* Spectral Observer type */ - else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') { + else if (argv[fa][1] == 'o') { fa = nfa; if (na == NULL) usage(); if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */ @@ -282,6 +311,13 @@ int main(int argc, char *argv[]) usage(); } + /* Gamut limit profile for first file */ + else if (argv[fa][1] == 'L') { + fa = nfa; + if (na == NULL) usage(); + strncpy(gprofname,na,MAXNAMEL-1); gprofname[MAXNAMEL-1] = '\000'; + } + /* Colorimeter Correction Matrix for second file */ else if (argv[fa][1] == 'X') { fa = nfa; @@ -313,6 +349,35 @@ int main(int argc, char *argv[]) if (fwacomp && spec == 0) error ("FWA compensation only works when viewer and/or illuminant selected"); + /* Gamut limit profile */ + if (gprofname[0] != '\000') { + int rv; + + if ((fp = new_icmFileStd_name(gprofname,"r")) == NULL) + error ("Can't open file '%s'",gprofname); + + if ((icco = new_icc()) == NULL) + error ("Creation of ICC object failed"); + + if ((rv = icco->read(icco,fp,0)) != 0) + error("Reading profile '%s' failed failed with error %d:'%s'\n", + gprofname, icco->errc, icco->err); + + if (icco->header->deviceClass != icSigInputClass + && icco->header->deviceClass != icSigDisplayClass + && icco->header->deviceClass != icSigOutputClass) + error("Profile '%s' must be a device profile to filter by gamut",gprofname); + + /* Wrap with an expanded icc */ + if ((xicco = new_xicc(icco)) == NULL) + error ("Creation of xicc failed"); + + /* Get a expanded color conversion object */ + if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST | ICX_FAST_SETUP, + icmFwd, icRelativeColorimetric, icSigXYZData, icmLuOrdNorm, NULL, NULL)) == NULL) + error ("%d, %s",xicco->errc, xicco->err); + } + /* Colorimeter Correction Matrix */ if (ccmxname[0] != '\000') { if ((cmx = new_ccmx()) == NULL) @@ -322,12 +387,14 @@ int main(int argc, char *argv[]) ccmxname, cmx->errc, cmx->err); } + /* Open up each file in turn, target then measured, */ /* and read in the CIE values. */ for (n = 0; n < 2; n++) { cgats *cgf = NULL; /* cgats file data */ int isLab = 0; /* 0 if file CIE is XYZ, 1 if is Lab */ int sidx; /* Sample ID index */ + int sldx = -1; /* Sample location index, < 0 if invalid */ int xix, yix, zix; /* Open CIE target values */ @@ -361,29 +428,41 @@ int main(int argc, char *argv[]) if (!spec && cgf->find_field(cgf, 0, "LAB_L") >= 0) isLab = 1; - cg[n].npat = cgf->t[0].nsets; /* Number of patches */ + cg[n].nig = cg[n].npat = cgf->t[0].nsets; /* Number of patches */ /* Figure out what sort of device it is */ { int ti; cg[n].isdisp = 0; + cg[n].isdnormed = 0; + cg[n].w[0] = cg[n].w[1] = cg[n].w[2] = 0.0; if ((ti = cgf->find_kword(cgf, 0, "DEVICE_CLASS")) < 0) error ("Input file '%s' doesn't contain keyword DEVICE_CLASS",cg[n].name); if (strcmp(cgf->t[0].kdata[ti],"DISPLAY") == 0) { cg[n].isdisp = 1; + cg[n].isdnormed = 1; /* Assume display type is normalised to 100 */ illum = icxIT_none; /* Displays are assumed to be self luminous */ /* ?? What if two files are different ?? */ } - /* See if the CIE data has been normalised to Y = 100 */ - if ((ti = cgf->find_kword(cgf, 0, "NORMALIZED_TO_Y_100")) < 0 - || strcmp(cgf->t[0].kdata[ti],"NO") == 0) { - cg[n].isdnormed = 0; - } else { - cg[n].isdnormed = 1; + if (cg[n].isdisp) { + + if ((ti = cgf->find_kword(cgf, 0, "LUMINANCE_XYZ_CDM2")) >= 0) { + if (sscanf(cgf->t[0].kdata[ti], " %lf %lf %lf ",&cg[n].w[0], &cg[n].w[1], &cg[n].w[2]) != 3) + cg[n].w[0] = cg[n].w[1] = cg[n].w[2] = 0.0; + } + + /* See if there is an explicit tag indicating data has been normalised to Y = 100 */ + if ((ti = cgf->find_kword(cgf, 0, "NORMALIZED_TO_Y_100")) >= 0) { + if (strcmp(cgf->t[0].kdata[ti],"NO") == 0) { + cg[n].isdnormed = 0; + } else { + cg[n].isdnormed = 1; + } + } } } @@ -410,6 +489,10 @@ int main(int argc, char *argv[]) && cgf->t[0].ftype[sidx] != cs_t) error("Sample ID/Name field isn't a quoted or non quoted character string"); + if ((sldx = cgf->find_field(cgf, 0, "SAMPLE_LOC")) < 0 + || cgf->t[0].ftype[sldx] != cs_t) + sldx = -1; + if (spec == 0) { /* Using instrument tristimulous value */ if (isLab) { /* Expect Lab */ @@ -443,24 +526,39 @@ int main(int argc, char *argv[]) for (i = 0; i < cg[n].npat; i++) { strcpy(cg[n].pat[i].sid, (char *)cgf->t[0].fdata[i][sidx]); - cg[n].pat[i].v[0] = *((double *)cgf->t[0].fdata[i][xix]); - cg[n].pat[i].v[1] = *((double *)cgf->t[0].fdata[i][yix]); - cg[n].pat[i].v[2] = *((double *)cgf->t[0].fdata[i][zix]); - - if (!isLab) { /* If XYZ */ - - /* If normalised to 100, scale back to 1.0 */ - if (!cg[n].isdisp || !cg[n].isdnormed) { - cg[n].pat[i].v[0] /= 100.0; /* scale back to 1.0 */ - cg[n].pat[i].v[1] /= 100.0; - cg[n].pat[i].v[2] /= 100.0; + if (sldx >= 0) + strcpy(cg[n].pat[i].loc, (char *)cgf->t[0].fdata[i][sldx]); + else + cg[n].pat[i].loc[0] = '\000'; + cg[n].pat[i].og = 0; + cg[n].pat[i].xyz[0] = *((double *)cgf->t[0].fdata[i][xix]); + cg[n].pat[i].xyz[1] = *((double *)cgf->t[0].fdata[i][yix]); + cg[n].pat[i].xyz[2] = *((double *)cgf->t[0].fdata[i][zix]); + + if (isLab) { /* Convert to XYZ */ + icmLab2XYZ(&icmD50, cg[n].pat[i].xyz, cg[n].pat[i].xyz); + } +//printf("~1 file %d patch %d = XYZ %f %f %f\n", n,i,cg[n].pat[i].xyz[0],cg[n].pat[i].xyz[1],cg[n].pat[i].xyz[2]); + + /* restore normalised display values to absolute */ + if (cg[n].isdnormed) { + if (cg[n].w[1] > 0.0) { + cg[n].pat[i].xyz[0] *= cg[n].w[1]/100.0; + cg[n].pat[i].xyz[1] *= cg[n].w[1]/100.0; + cg[n].pat[i].xyz[2] *= cg[n].w[1]/100.0; } - } else { /* If Lab */ - icmLab2XYZ(&icmD50, cg[n].pat[i].v, cg[n].pat[i].v); + + } else if (!cg[n].isdisp) { + /* If reflective or transmissive that are 0..100%, */ + /* scale back to 0.. 1 */ + cg[n].pat[i].xyz[0] /= 100.0; /* scale back to XYZ 1.0 */ + cg[n].pat[i].xyz[1] /= 100.0; + cg[n].pat[i].xyz[2] /= 100.0; } + /* Apply ccmx */ if (n == 1 && cmx != NULL) { - cmx->xform(cmx, cg[n].pat[i].v, cg[n].pat[i].v); + cmx->xform(cmx, cg[n].pat[i].xyz, cg[n].pat[i].xyz); } } @@ -563,6 +661,11 @@ int main(int argc, char *argv[]) for (i = 0; i < cg[0].npat; i++) { strcpy(cg[n].pat[i].sid, (char *)cgf->t[0].fdata[i][sidx]); + if (sldx >= 0) + strcpy(cg[n].pat[i].loc, (char *)cgf->t[0].fdata[i][sldx]); + else + cg[n].pat[i].loc[0] = '\000'; + cg[n].pat[i].og = 0; /* Read the spectral values for this patch */ for (j = 0; j < sp.spec_n; j++) { @@ -570,11 +673,21 @@ int main(int argc, char *argv[]) } /* Convert it to XYZ space */ - sp2cie->convert(sp2cie, cg[n].pat[i].v, &sp); + sp2cie->convert(sp2cie, cg[n].pat[i].xyz, &sp); + + /* restore normalised display values to absolute */ + if (cg[n].isdnormed) { + if (cg[n].w[1] > 0.0) { + cg[n].pat[i].xyz[0] *= cg[n].w[1]; + cg[n].pat[i].xyz[1] *= cg[n].w[1]; + cg[n].pat[i].xyz[2] *= cg[n].w[1]; + } - /* Applu ccmx */ + } + + /* Apply ccmx */ if (n == 1 && cmx != NULL) { - cmx->xform(cmx, cg[n].pat[i].v, cg[n].pat[i].v); + cmx->xform(cmx, cg[n].pat[i].xyz, cg[n].pat[i].xyz); } } @@ -583,31 +696,68 @@ int main(int argc, char *argv[]) } /* End of reading in CGATs file */ - /* Normalise this file to white = 1.0 or D50 */ + /* Locate the patch with maximum Y, a possible white patch */ if (norm) { - double bxyz[3] = { 0.0, -100.0, 0.0 }; + int ii; - /* Locate patch with biggest Y */ - for (i = 0; i < cg[n].npat; i++) { - double xyz[3]; - icmLab2XYZ(&icmD50, xyz, cg[n].pat[i].v); - if (cg[n].pat[i].v[1] > bxyz[1]) { - icmCpy3(bxyz, cg[n].pat[i].v); + if (cg[n].w[1] == 0.0) { /* No white patch */ + + /* Locate patch with biggest Y, assume it is white... */ + for (i = 0; i < cg[n].npat; i++) { + if (cg[n].pat[i].xyz[1] > cg[n].w[1]) { + icmCpy3(cg[n].w, cg[n].pat[i].xyz); + ii = i; + } } + if (verb) printf("File %d Chose patch %d as white, xyz %f %f %f\n", + n, ii+1,cg[n].w[0],cg[n].w[1],cg[n].w[2]); + } else { + if (verb) printf("File %d White is from display luminance ref. xyz %f %f %f\n", + n, cg[n].w[0],cg[n].w[1],cg[n].w[2]); + } + icmCpy3(cg[n].nw, cg[n].w); + } + + + /* Normalise this file to white = 1.0 or D50 */ + if (norm) { + int ii; + + double chmat[3][3]; /* Chromatic adapation matrix */ + + if (norm == 2) { /* Norm to white XYZ */ + icmXYZNumber s_wp; + icmAry2XYZ(s_wp, cg[n].w); + icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, s_wp, chmat); } - /* Then normalize all the values */ for (i = 0; i < cg[n].npat; i++) { if (norm == 1) { - cg[n].pat[i].v[0] /= bxyz[1]; - cg[n].pat[i].v[1] /= bxyz[1]; - cg[n].pat[i].v[2] /= bxyz[1]; + cg[n].pat[i].xyz[0] *= 100.0 / cg[n].w[1]; + cg[n].pat[i].xyz[1] *= 100.0 / cg[n].w[1]; + cg[n].pat[i].xyz[2] *= 100.0 / cg[n].w[1]; + } else if (norm == 2) { + icmMulBy3x3(cg[n].pat[i].xyz, chmat, cg[n].pat[i].xyz); } else { - cg[n].pat[i].v[0] *= icmD50.X/bxyz[0]; - cg[n].pat[i].v[1] *= icmD50.Y/bxyz[1]; - cg[n].pat[i].v[2] *= icmD50.Z/bxyz[2]; + cg[n].pat[i].xyz[0] *= 100.0 / (cg[n].w[0] + cg[n].w[1] + cg[n].w[2]); + cg[n].pat[i].xyz[1] *= 100.0 / (cg[n].w[0] + cg[n].w[1] + cg[n].w[2]); + cg[n].pat[i].xyz[2] *= 100.0 / (cg[n].w[0] + cg[n].w[1] + cg[n].w[2]); } +//printf("~1 file %d patch %d = norm XYZ %f %f %f\n", n,i,cg[n].pat[i].xyz[0],cg[n].pat[i].xyz[1],cg[n].pat[i].xyz[2]); } + /* Compute normalised white too */ + if (norm == 1) { + cg[n].nw[0] *= 100.0 / cg[n].w[1]; + cg[n].nw[1] *= 100.0 / cg[n].w[1]; + cg[n].nw[2] *= 100.0 / cg[n].w[1]; + } else if (norm == 2) { + icmMulBy3x3(cg[n].nw, chmat, cg[n].w); + } else { + cg[n].nw[0] *= 100.0 / (cg[n].w[0] + cg[n].w[1] + cg[n].w[2]); + cg[n].nw[1] *= 100.0 / (cg[n].w[0] + cg[n].w[1] + cg[n].w[2]); + cg[n].nw[2] *= 100.0 / (cg[n].w[0] + cg[n].w[1] + cg[n].w[2]); + } +//printf("~1 file %d norm white XYZ %f %f %f\n", n,cg[n].nw[0], cg[n].nw[1], cg[n].nw[2]); } cgf->del(cgf); /* Clean up */ } @@ -634,19 +784,46 @@ int main(int argc, char *argv[]) } } - /* Adjust the reference white Y to be larger than the largest Y of the two files */ - if (!usestdd50) { - double maxy = -1e6; - - for (n = 0; n < 2; n++) { - for (i = 0; i < cg[n].npat; i++) { - if (cg[n].pat[i].v[1] > maxy) - maxy = cg[n].pat[i].v[1]; + /* Figure out which patches to skip because they are out of gamut */ + if (luo != NULL) { + double chmat[3][3]; /* Chromatic adapation matrix */ + double out[MAX_CHAN], in[3], check[3]; + icmXYZNumber s_wp; + int rv; + + /* Convert sample PCS to relative */ + icmAry2XYZ(s_wp, cg[0].nw); + icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, s_wp, chmat); + + for (i = 0; i < cg[0].npat; i++) { + icmMulBy3x3(in, chmat, cg[0].pat[i].xyz); +//printf("~1 %d: xyz %f %f %f, rel %f %f %f\n", i+1, cg[0].pat[i].xyz[0], cg[0].pat[i].xyz[1], cg[0].pat[i].xyz[2], in[0], in[1], in[2]); + + if ((rv = luo->inv_lookup(luo, out, in)) > 0 || 1) { + double de; + + luo->lookup(luo, check, out); + de = icmXYZLabDE(&icmD50,check, in); +//printf("~1 %d: rv %d, de %f, check XYZ %f %f %f\n",i+1,rv, de, check[0],check[1],check[2]); + + if (de >= 0.01) { + cg[0].pat[i].og = 1; +//printf("~1 Patch %d is out of gamut by DE %f RGB %f %f %f\n",i+1,de,out[0],out[1],out[2]); + if (verb >= 3) + printf("Patch %d is out of gamut by DE %f\n",i+1,de); + cg[0].nig--; + } } } - labw.X *= maxy/icmD50.Y; /* Scale white uniformly */ - labw.Y *= maxy/icmD50.Y; /* Scale white uniformly */ - labw.Z *= maxy/icmD50.Y; + if (verb) + fprintf(verbo,"No of test patches in gamut = %d/%d\n",cg[0].npat - cg[0].nig,cg[0].npat); + } + + /* Adjust the Lab reference white to be the mean of the white of the two files */ + if (norm != 0 && !usestdd50) { + labw.X = 0.5 * (cg[0].nw[0] + cg[1].nw[0]); + labw.Y = 0.5 * (cg[0].nw[1] + cg[1].nw[1]); + labw.Z = 0.5 * (cg[0].nw[2] + cg[1].nw[2]); if (verb) printf("L*a*b* white reference = XYZ %f %f %f\n",labw.X,labw.Y,labw.Z); @@ -655,18 +832,30 @@ int main(int argc, char *argv[]) /* Convert XYZ to Lab */ for (n = 0; n < 2; n++) { for (i = 0; i < cg[n].npat; i++) { - icmXYZ2Lab(&labw, cg[n].pat[i].v, cg[n].pat[i].v); + icmXYZ2Lab(&labw, cg[n].pat[i].v, cg[n].pat[i].xyz); } } /* Compute the delta E's */ for (i = 0; i < cg[0].npat; i++) { + + if (cg[0].pat[i].og) /* Skip out of gamut patches */ + continue; + + cg[0].pat[i].ixde[0] = fabs(cg[0].pat[i].xyz[0] - cg[1].pat[match[i]].xyz[0]); + cg[0].pat[i].ixde[1] = fabs(cg[0].pat[i].xyz[1] - cg[1].pat[match[i]].xyz[1]); + cg[0].pat[i].ixde[2] = fabs(cg[0].pat[i].xyz[2] - cg[1].pat[match[i]].xyz[2]); + if (cie2k) cg[0].pat[i].de = icmCIE2K(cg[0].pat[i].v, cg[1].pat[match[i]].v); else if (cie94) cg[0].pat[i].de = icmCIE94(cg[0].pat[i].v, cg[1].pat[match[i]].v); else cg[0].pat[i].de = icmLabDE(cg[0].pat[i].v, cg[1].pat[match[i]].v); + + cg[0].pat[i].ide[0] = fabs(cg[0].pat[i].v[0] - cg[1].pat[match[i]].v[0]); + cg[0].pat[i].ide[1] = fabs(cg[0].pat[i].v[1] - cg[1].pat[match[i]].v[1]); + cg[0].pat[i].ide[2] = fabs(cg[0].pat[i].v[2] - cg[1].pat[match[i]].v[2]); } /* Create sorted list, from worst to best. */ @@ -688,6 +877,8 @@ int main(int argc, char *argv[]) int n10; double merr10 = 0.0, aerr10 = 0.0; double rad; + double aierr[3] = { 0.0, 0.0, 0.0 }; + double aixerr[3] = { 0.0, 0.0, 0.0 }; if (dovrml) { wrl = new_vrml(out_name, doaxes, 0); @@ -700,6 +891,10 @@ int main(int argc, char *argv[]) /* Do overall results */ for (i = 0; i < cg[0].npat; i++) { double de; + + if (cg[0].pat[i].og) /* Skip out of gamut patches */ + continue; + if (dosort) j = sort[i]; else @@ -708,12 +903,29 @@ int main(int argc, char *argv[]) de = cg[0].pat[j].de; aerr += de; - if (verb) { - printf("%s: %f %f %f <=> %f %f %f de %f\n", + aierr[0] += cg[0].pat[j].ide[0]; + aierr[1] += cg[0].pat[j].ide[1]; + aierr[2] += cg[0].pat[j].ide[2]; + + aixerr[0] += cg[0].pat[j].ixde[0]; + aixerr[1] += cg[0].pat[j].ixde[1]; + aixerr[2] += cg[0].pat[j].ixde[2]; + + if (verb >= 2) { + + printf("%s%s%s: %f %f %f <=> %f %f %f de %f\n", cg[0].pat[j].sid, + cg[0].pat[j].loc[0] != '\000' ? " " : "", + cg[0].pat[j].loc, cg[0].pat[j].v[0], cg[0].pat[j].v[1], cg[0].pat[j].v[2], cg[1].pat[match[j]].v[0], cg[1].pat[match[j]].v[1], cg[1].pat[match[j]].v[2], de); + +#ifdef NEVER /* Print XYZ as well */ + printf(" %f %f %f <=> %f %f %f\n", + cg[0].pat[j].xyz[0], cg[0].pat[j].xyz[1], cg[0].pat[j].xyz[2], + cg[1].pat[match[j]].xyz[0], cg[1].pat[match[j]].xyz[1], cg[1].pat[match[j]].xyz[2]); +#endif } if (de > merr) @@ -731,8 +943,16 @@ int main(int argc, char *argv[]) } } - if (cg[0].npat > 0) - aerr /= (double)cg[0].npat; + if (cg[0].nig > 0) { + aerr /= (double)cg[0].nig; + aierr[0] /= (double)cg[0].nig; + aierr[1] /= (double)cg[0].nig; + aierr[2] /= (double)cg[0].nig; + + aixerr[0] /= (double)cg[0].nig; + aixerr[1] /= (double)cg[0].nig; + aixerr[2] /= (double)cg[0].nig; + } if (dovrml) { wrl->make_lines(wrl, 0, 2); @@ -741,23 +961,33 @@ int main(int argc, char *argv[]) } /* Do best 90% */ - n90 = (int)(cg[0].npat * 9.0/10.0 + 0.5); - for (i = (cg[0].npat-n90); i < cg[0].npat; i++) { + n90 = (int)(cg[0].nig * 9.0/10.0 + 0.5); + for (i = j = 0; i < cg[0].npat; i++) { double de = cg[0].pat[sort[i]].de; - aerr90 += de; - if (de > merr90) - merr90 = de; + if (cg[0].pat[i].og) /* Skip out of gamut */ + continue; + if (j >= (cg[0].nig-n90)) { /* If in top 90% of in gamut patches */ + aerr90 += de; + if (de > merr90) + merr90 = de; + } + j++; /* Index of within gamut patches */ } if (n90 > 0) aerr90 /= (double)n90; /* Do worst 10% */ - n10 = (int)(cg[0].npat * 1.0/10.0 + 0.5); - for (i = 0; i < n10; i++) { + n10 = (int)(cg[0].nig * 1.0/10.0 + 0.5); + for (i = j = 0; i < cg[0].npat; i++) { double de = cg[0].pat[sort[i]].de; - aerr10 += de; - if (de > merr10) - merr10 = de; + if (cg[0].pat[i].og) /* Skip out of gamut */ + continue; + if (j <= n10) { /* If in worst 10% of in gamut patches */ + aerr10 += de; + if (de > merr10) + merr10 = de; + } + j++; } if (n10 > 0) aerr10 /= (double)n10; @@ -770,6 +1000,8 @@ int main(int argc, char *argv[]) printf(" Total errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr, aerr); printf(" Worst 10%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr10, aerr10); printf(" Best 90%% errors%s: peak = %f, avg = %f\n", cie2k ? " (CIEDE2000)" : cie94 ? " (CIE94)" : "", merr90, aerr90); + printf(" avg err X %f, Y %f, Z %f\n", aixerr[0], aixerr[1], aixerr[2]); + printf(" avg err L* %f, a* %f, b* %f\n", aierr[0], aierr[1], aierr[2]); free(sort); free(match); @@ -777,6 +1009,15 @@ int main(int argc, char *argv[]) free(cg[1].pat); } + if (luo != NULL) + luo->del(luo); + if (xicco != NULL) + xicco->del(xicco); /* Expansion wrapper */ + if (icco != NULL) + icco->del(icco); /* Icc */ + if (fp != NULL) + fp->del(fp); + return 0; } diff --git a/profile/prof.h b/profile/prof.h index 074bb73..6013d99 100644 --- a/profile/prof.h +++ b/profile/prof.h @@ -49,6 +49,7 @@ void make_output_icc( int gamdiag, /* Make gamut mapping diagnostic wrl plots */ int verify, /* nz to print verification */ int clipprims, /* Clip white, black and primaries */ + double wpscale, /* >= 0.0 for media white point scale factor */ icxInk *ink, /* Ink limit/black generation setup */ char *in_name, /* input .ti3 file name */ char *file_name, /* output icc name */ @@ -62,6 +63,7 @@ void make_output_icc( int fwacomp, /* FWA compensation requested */ double smooth, /* RSPL smoothing factor, -ve if raw */ double avgdev, /* reading Average Deviation as a proportion of the input range */ + double demph, /* Emphasise dark region grid resolution in cLUT */ char *ipname, /* input icc profile - enables gamut map, NULL if none */ char *sgname, /* source image gamut - NULL if none */ char *absname[3], /* abstract profile name for each table */ diff --git a/profile/profcheck.c b/profile/profcheck.c index ca9b0b2..1895713 100644 --- a/profile/profcheck.c +++ b/profile/profcheck.c @@ -507,7 +507,7 @@ int main(int argc, char *argv[]) /* Read in the CGATs fields */ { int sidx; /* Sample ID index */ - int sloc; /* Sample location indexi (if any) */ + int sloc; /* Sample location index (if any) */ int ti, ci, mi, yi, ki; int Xi, Yi, Zi; diff --git a/profile/profin.c b/profile/profin.c index 2f74ec2..c703c42 100644 --- a/profile/profin.c +++ b/profile/profin.c @@ -825,6 +825,8 @@ make_input_icc( flags |= ICX_SET_BLACK; /* Compute & use black */ flags |= ICX_SET_WHITE; /* Compute & use white */ + + /* ICX_SET_WHITE_C isn't applicable to matrix profiles */ if (autowpsc) flags |= ICX_SET_WHITE_US; /* Compute & use white without scaling to L */ @@ -836,7 +838,7 @@ make_input_icc( wr_xicc, icmFwd, icmDefaultIntent, icmLuOrdNorm, flags, /* Flags */ - npat, npat, tpat, NULL, 0.0, wpscale, smooth, avgdev, + npat, npat, tpat, NULL, 0.0, wpscale, smooth, avgdev, 1.0, NULL, NULL, NULL, iquality)) == NULL) error("%d, %s",wr_xicc->errc, wr_xicc->err); @@ -1121,7 +1123,7 @@ make_input_icc( ICX_2PASSSMTH | #endif flags, /* Flags */ - npat + nxpat, npat, tpat, NULL, 0.0, wpscale, smooth, avgdev, + npat + nxpat, npat, tpat, NULL, 0.0, wpscale, smooth, avgdev, 1.0, NULL, NULL, NULL, iquality)) == NULL) error ("%d, %s",wr_xicc->errc, wr_xicc->err); @@ -1207,7 +1209,8 @@ make_input_icc( NULL, NULL, /* Use default Lab' range */ in_b2a_clut, /* Lab' -> Device' transfer function */ NULL, NULL, /* Use default Device' range */ - in_b2a_output) != 0) /* Output transfer function, Device'->Device */ + in_b2a_output, /* Output transfer function, Device'->Device */ + NULL, NULL) != 0) /* Use default APXLS range */ error("Setting 16 bit PCS->Device Lut failed: %d, %s",wr_icco->errc,wr_icco->err); if (cx.verb) { printf("\n"); diff --git a/profile/profout.c b/profile/profout.c index d89ae4e..8c6fa0d 100644 --- a/profile/profout.c +++ b/profile/profout.c @@ -65,6 +65,7 @@ #undef IMP_MONO /* [Undef] Turn on development code */ +#define EMPH_DISP_BLACKPOINT /* [Define] Increase weight near diplay black point */ #define NO_B2A_PCS_CURVES /* [Define] PCS curves seem to make B2A less accurate. Why ? */ #define USE_CAM_CLIP_OPT /* [Define] Clip out of gamut in CAM space rather than PCS */ #define USE_LEASTSQUARES_APROX /* [Define] Use least squares fitting approximation in B2A */ @@ -73,7 +74,7 @@ #undef DISABLE_GAMUT_TAG /* [Undef] To disable gamut tag */ #undef WARN_CLUT_CLIPPING /* [Undef] Print warning if setting clut clips */ #undef COMPARE_INV_CLUT /* [Undef] Compare result of inv_clut with clut to diag inv probs */ -#define FILTER_B2ACLIP /* [Define] Filter clip area of B2A */ +#undef FILTER_B2ACLIP /* [Undef] Filter clip area of B2A (Causes reversal problems) */ #define FILTER_THR_DE 3.0 /* [5.0] Filtering threshold DE */ #define FILTER_MAX_DE 5.0 /* [10.0] Filtering DE to gamut surface at whit MAX_RAD starts */ #define FILTER_MAX_RAD 0.1 /* [0.1] Filtering maximum radius in grid */ @@ -185,7 +186,7 @@ typedef struct { double swxyz[3]; /* Source white point in XYZ */ gamut *gam; /* Output gamut object for setting gamut Lut */ - int wantLab; /* 0 if want is XYZ PCS, 1 want is Lab PCS */ + int wantLab; /* 0 if is XYZ PCS, 1 if is Lab PCS */ } out_b2a_callback; /* Utility to handle abstract profile application to PCS. */ @@ -642,6 +643,7 @@ make_output_icc( int gamdiag, /* Make gamut mapping diagnostic wrl plots */ int verify, /* nz to print verification */ int clipprims, /* Clip white, black and primaries */ + double wpscale, /* >= 0.0 for media white point scale factor */ icxInk *oink, /* Ink limit/black generation setup (NULL if n/a) */ char *in_name, /* input .ti3 file name */ char *file_name, /* output icc name */ @@ -655,6 +657,7 @@ make_output_icc( int fwacomp, /* FWA compensation requested */ double smooth, /* RSPL smoothing factor, -ve if raw */ double avgdev, /* reading Average Deviation as a proportion of the input range */ + double demph, /* Emphasise dark region grid resolution in cLUT */ char *ipname, /* input icc profile - enables gamut map, NULL if none */ char *sgname, /* source image gamut - NULL if none */ char *absname[3], /* abstract profile name for each table */ @@ -737,7 +740,7 @@ make_output_icc( int ti; if ((ti = icg->find_kword(icg, 0, "LUMINANCE_XYZ_CDM2")) >= 0) { - if (sscanf(icg->t[0].kdata[ti], " %*lf %lf %*lf ",&dispLuminance) != 1) + if (sscanf(icg->t[0].kdata[ti], " %*f %lf %*f ",&dispLuminance) != 1) dispLuminance = 0.0; } @@ -1215,6 +1218,17 @@ make_output_icc( cc = 0.0; else if (cc > 1.0) cc = 1.0; + + if (cal->tvenc) { + cc = (cc * (235.0-16.0) + 16.0)/255.0; + + /* For video encoding the extra bits of precision are created by bit shifting */ + /* rather than scaling, so we need to scale the fp value to account for this. */ + /* We assume the precision is the vcgt table size = 16 */ + /* ~~99 ideally we should tag the fact that this is video encoded, so that */ + /* the vcgt loaded can adjust for a different bit precision ~~~~ */ + cc = (cc * 255 * (1 << (16 - 8)))/((1 << 16) - 1.0); + } ((unsigned short*)wo->u.table.data)[ncal * j + i] = (int)(cc * 65535.0 + 0.5); } } @@ -1389,12 +1403,12 @@ make_output_icc( wog->allocate((icmBase *)wog); wob->allocate((icmBase *)wob); - wor->data[0].X = 1.0; wor->data[0].Y = 0.0; wor->data[0].Z = 0.0; - wog->data[0].X = 0.0; wog->data[0].Y = 1.0; wog->data[0].Z = 0.0; - wob->data[0].X = 0.0; wob->data[0].Y = 0.0; wob->data[0].Z = 1.0; +// wor->data[0].X = 1.0; wor->data[0].Y = 0.0; wor->data[0].Z = 0.0; +// wog->data[0].X = 0.0; wog->data[0].Y = 1.0; wog->data[0].Z = 0.0; +// wob->data[0].X = 0.0; wob->data[0].Y = 0.0; wob->data[0].Z = 1.0; /* Setup deliberately wrong dummy values (channels rotated). */ - /* icxMatrix may override override these later */ + /* icxMatrix may override these later */ wor->data[0].X = 0.143066; wor->data[0].Y = 0.060608; wor->data[0].Z = 0.714096; wog->data[0].X = 0.436066; wog->data[0].Y = 0.222488; wog->data[0].Z = 0.013916; wob->data[0].X = 0.385147; wob->data[0].Y = 0.716873; wob->data[0].Z = 0.097076; @@ -1834,6 +1848,8 @@ make_output_icc( } + isLab = wantLab; /* We now have what we want */ + /* Normalize display values to Y = 1.0 if needed */ /* (re-norm spec derived, since observer may be different) */ if (isdisp && (isdnormed == 0 || spec != 0)) { @@ -1878,6 +1894,51 @@ make_output_icc( } } /* End of reading in CGATs file */ + +#ifdef EMPH_DISP_BLACKPOINT + /* Add extra weighting to sample points near black for additive display. */ + /* Not sure what the justification is, apart from making the black */ + /* point more accurately modelled. Does this reflect an underlying */ + /* problem with rspl in perceptual space ? Or is it a reflection */ + /* of the possible "scaled" viewing mode of additive display */ + /* usage ? What about print and scan ?? */ + if (isdisp && (imask == ICX_W || imask == ICX_RGB)) { + double minL = 1e6;; + + /* Locate the lowest L* value */ + for (i = 0; i < npat; i++) { + if (wantLab) { + if (tpat[i].v[0] < minL) + minL = tpat[i].v[0]; + } else { + double lab[2]; + icmXYZ2Lab(&icmD50, lab, tpat[i].v); + if (lab[0] < minL) + minL = lab[0]; + } + } + + /* Compute weighting factor */ + /* (Hard to guess what numbers to put in here.. */ + for (i = 0; i < npat; i++) { + double lab[3], L; + if (wantLab) { + L = tpat[i].v[0]; + } else { + icmXYZ2Lab(&icmD50, lab, tpat[i].v); + L = lab[0]; + } + L -= minL; + L /= 20.0; /* Just weight over 20 L* range */ + if (L > 1.0) + continue; + L = 1.0 + 19.0 * pow(1.0 - L, 3.0); + tpat[i].w *= L; +//printf("~1 pat %d %f %f %f weight %f\n", i,tpat[i].p[0], tpat[i].p[1], tpat[i].p[2], tpat[i].w); + } + } +#endif /* EMPH_DISP_BLACKPOINT */ + if (isLut) { xicc *wr_xicc; /* extention object */ icxLuBase *AtoB; /* AtoB ixcLu */ @@ -1920,7 +1981,7 @@ make_output_icc( ICX_2PASSSMTH | #endif flags, - npat, npat, tpat, NULL, dispLuminance, -1.0, smooth, avgdev, + npat, npat, tpat, NULL, dispLuminance, wpscale, smooth, avgdev, demph, NULL, oink, cal, iquality)) == NULL) error("%d, %s",wr_xicc->errc, wr_xicc->err); @@ -2016,18 +2077,20 @@ make_output_icc( vc->Lv = v->Lv; if (v->Yf >= 0.0) vc->Yf = v->Yf; - if (v->Fxyz[0] >= 0.0 && v->Fxyz[1] > 0.0 && v->Fxyz[2] >= 0.0) { + if (v->Yg >= 0.0) + vc->Yg = v->Yg; + if (v->Gxyz[0] >= 0.0 && v->Gxyz[1] > 0.0 && v->Gxyz[2] >= 0.0) { /* Normalise XYZ to current media white */ - vc->Fxyz[0] = v->Fxyz[0]/v->Fxyz[1] * vc->Fxyz[1]; - vc->Fxyz[2] = v->Fxyz[2]/v->Fxyz[1] * vc->Fxyz[1]; + vc->Gxyz[0] = v->Gxyz[0]/v->Gxyz[1] * vc->Gxyz[1]; + vc->Gxyz[2] = v->Gxyz[2]/v->Gxyz[1] * vc->Gxyz[1]; } - if (v->Fxyz[0] >= 0.0 && v->Fxyz[1] >= 0.0 && v->Fxyz[2] < 0.0) { + if (v->Gxyz[0] >= 0.0 && v->Gxyz[1] >= 0.0 && v->Gxyz[2] < 0.0) { /* Convert Yxy to XYZ */ - double x = v->Fxyz[0]; - double y = v->Fxyz[1]; /* If Y == 1.0, then X+Y+Z = 1/y */ + double x = v->Gxyz[0]; + double y = v->Gxyz[1]; /* If Y == 1.0, then X+Y+Z = 1/y */ double z = 1.0 - x - y; - vc->Fxyz[0] = x/y * vc->Fxyz[1]; - vc->Fxyz[2] = z/y * vc->Fxyz[1]; + vc->Gxyz[0] = x/y * vc->Gxyz[1]; + vc->Gxyz[2] = z/y * vc->Gxyz[1]; } } @@ -2182,31 +2245,40 @@ make_output_icc( /* cx.ix and cx.ox for each intent, but that would be expensive!. */ if (sepsat && (pgmi->usecas & 0xff) != (sgmi->usecas & 0xff)) error("Can't handle percept and sat table intents with different CAM spaces"); - /* Default perceptual input gamut mapping space is absolute perceptual */ - intentp = noptop ? icAbsoluteColorimetric : icmAbsolutePerceptual; - /* But override this for apperance space gamut mapping */ - if ((pgmi->usecas & 0xff) != 0x0) { + /* If apperance space perceptual table gamut mapping */ + if ((pgmi->usecas & 0xff) >= 0x2) { intentp = noptop ? icxAppearance : icxPerceptualAppearance; + } else { + if ((pgmi->usecas & 0xff) == 0x0) + intentp = noptop ? icRelativeColorimetric : icPerceptual; + else /* pgmi->usecas & 0xff == 0x1 */ + intentp = noptop ? icAbsoluteColorimetric : icmAbsolutePerceptual; } + if (sepsat) { - /* Default saturation gamut mapping space is absolute saturation */ - intents = nostos ? icAbsoluteColorimetric : icmAbsoluteSaturation; - /* But override this for apperance space gamut mapping */ - if ((sgmi->usecas & 0xff) != 0x0) { + /* If apperance space saturation table gamut mapping */ + if ((sgmi->usecas & 0xff) >= 0x2) { intents = nostos ? icxAppearance : icxSaturationAppearance; + } else { + if ((sgmi->usecas & 0xff) == 0x0) + intents = nostos ? icRelativeColorimetric : icSaturation; + else + intents = nostos ? icAbsoluteColorimetric : icmAbsoluteSaturation; } } - /* Default output gamut mapping space is absolute colorimetric */ - intento = icAbsoluteColorimetric; - /* But override this for apperance space gamut mapping */ - if ((pgmi->usecas & 0xff) != 0x0) { + if ((pgmi->usecas & 0xff) >= 0x2) { intento = icxAppearance; + } else { + if ((pgmi->usecas & 0xff) == 0x0) + intento = icRelativeColorimetric; + else /* pgmi->usecas & 0xff == 0x1 */ + intento = icAbsoluteColorimetric; } - if ((pgmi->usecas & 0xff) == 0x2) { + if ((pgmi->usecas & 0xff) == 0x3) { /* Abs. appearance */ double mxw; intentp = intents = intento = icxAbsAppearance; @@ -2274,7 +2346,7 @@ make_output_icc( if (sgname != NULL) { /* Optional source gamut - ie. from an images */ int isJab = 0; - if ((pgmi->usecas & 0xff) != 0) + if ((pgmi->usecas & 0xff) >= 0x2) isJab = 1; if (verb) @@ -2628,14 +2700,16 @@ make_output_icc( ICM_CLUT_SET_FILTER | #endif 0, - &cx, /* Context */ - cx.pcsspace, /* Input color space */ - devspace, /* Output color space */ - out_b2a_input, /* Input transform PCS->PCS' */ - NULL, NULL, /* Use default PCS range */ - out_b2a_clut, /* Lab' -> Device' transfer function */ - NULL, NULL, /* Use default Device' range */ - out_b2a_output) != 0) /* Output transfer function, Device'->Device */ + &cx, /* Context */ + cx.pcsspace, /* Input color space */ + devspace, /* Output color space */ + out_b2a_input, /* Input transform PCS->PCS' */ + NULL, NULL, /* Use default PCS range */ + out_b2a_clut, /* Lab' -> Device' transfer function */ + NULL, NULL, /* Use default Device' range */ + out_b2a_output, /* Output transfer function, Device'->Device */ + NULL, NULL /* Use default APXLS range */ + ) != 0) error("Setting 16 bit PCS->Device Lut failed: %d, %s",wr_icco->errc,wr_icco->err); if (cx.verb) { printf("\n"); @@ -2769,7 +2843,9 @@ make_output_icc( NULL, NULL, /* Use default Lab' range */ PCSp_bdist, /* Lab' -> Boundary distance */ NULL, NULL, /* Use default Device' range */ - gamut_output) != 0) /* Boundary distance to out of gamut value */ + gamut_output, /* Boundary distance to out of gamut value */ + NULL, NULL + ) != 0) error("Setting 16 bit PCS->Device Gamut Lut failed: %d, %s",wr_icco->errc,wr_icco->err); #endif /* !DEBUG_ONE */ if (cx.verb) { @@ -2823,7 +2899,7 @@ make_output_icc( wr_xicc, icmFwd, isdisp ? icmDefaultIntent : icRelativeColorimetric, icmLuOrdRev, flags, /* Compute white & black */ - npat, npat, tpat, NULL, dispLuminance, -1.0, smooth, avgdev, + npat, npat, tpat, NULL, dispLuminance, wpscale, smooth, avgdev, demph, NULL, oink, cal, iquality)) == NULL) error("%d, %s",wr_xicc->errc, wr_xicc->err); diff --git a/profile/txt2ti3.c b/profile/txt2ti3.c index 9b425f3..62807f3 100644 --- a/profile/txt2ti3.c +++ b/profile/txt2ti3.c @@ -28,7 +28,7 @@ */ -#undef DEBUG +#define DEBUG #include <stdio.h> #include <stdlib.h> @@ -50,7 +50,7 @@ usage(char *mes) { fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n"); if (mes != NULL) fprintf(stderr,"error: %s\n",mes); - fprintf(stderr,"usage: txt2ti3 [-v] [-l limit] [devfile] infile [specfile] outfile\n"); + fprintf(stderr,"usage: txt2ti3 [-v] [-l limit] [devfile] infile [specfile] outbase\n"); /* fprintf(stderr," -v Verbose mode\n"); */ fprintf(stderr," -2 Create dummy .ti2 file as well\n"); fprintf(stderr," -l limit set ink limit, 0 - 400%% (default max in file)\n"); @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) cmy->add_other(cmy, "ECI2002"); /* Gretag/Logo Target file */ cmy->add_other(cmy, ""); /* Wildcard */ if (cmy->read_name(cmy, devname)) - error ("Read: Can't read dev file '%s'. Unknown format or corrupted file ?",devname); + error ("Read: Can't read dev file '%s'. Unknown format or corrupted file ? (%s)",devname,cmy->err); if (cmy->ntables != 1) warning("Input file '%s' doesn't contain exactly one table",devname); |